Feature/refactor architecture (#5)

* Refactor everything under one namespace, turn most things into classes, add support for selecting ROI in cameraHandler, add state management

* Remove unsued main.py file - other projects are working on that implementation
This commit is contained in:
Zdzislaw Goik 2022-03-20 15:24:28 +01:00 committed by GitHub
parent b6b44dc978
commit b788823375
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 425 additions and 419 deletions

13
ESP/include/GlobalVars.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#ifndef GLOBALVARS_H
#define GLOBALVARS_H
#include "StateManager.h"
#include "LEDManager.h"
#include "cameraHandler.h"
extern OpenIris::LEDManager ledManager;
extern OpenIris::StateManager stateManager;
extern OpenIris::CameraHandler cameraHandler;
#endif

View File

@ -1,20 +1,19 @@
#pragma once
#include <Arduino.h>
namespace LEDManager{
namespace OpenIris{
enum Status {
ConnectingToWifi = 1,
ConnectingToWifiError = 2,
ConnectingToWifiSuccess = 3,
ServerError = 3,
CameraError = 4
class LEDManager{
private:
uint8_t ledPin;
public:
explicit LEDManager(uint8_t pin) : ledPin(pin) {}
void setupLED() const;
void on() const;
void off() const;
void blink(unsigned int time);
void displayStatus();
};
extern uint8_t ledPin;
void setupLED();
void on();
void off();
void blink(unsigned int time);
void displayPattern(Status status);
}

View File

@ -1,57 +1,59 @@
#pragma once
#include <ArduinoOTA.h>
namespace OpenIris{
class OTA {
private:
unsigned long bootTimestamp = 0;
bool isOtaEnabled = true;
public:
void SetupOTA(const char *OTAPassword, uint16_t OTAServerPort) {
Serial.println("Setting up OTA updates");
namespace OTA{
unsigned long boot_timestamp = 0;
bool is_ota_eabled = true;
void SetupOTA(const char* OTAPassword, uint16_t OTAServerPort){
Serial.println("Setting up OTA updates");
if(OTAPassword == '\0'){
Serial.println("THE PASSWORD IS REQUIRED, [[ABORTING]]");
return;
}
ArduinoOTA.setPort(OTAServerPort);
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
})
.onEnd([]() {
Serial.println("OTA updated finished successfully!");
})
.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
Serial.println("Starting up basic OTA server");
Serial.println("OTA will be live for 30s, after which it will be disabled until restart");
ArduinoOTA.begin();
boot_timestamp = millis();
}
void HandleOTAUpdate(){
if(is_ota_eabled){
if(boot_timestamp + 30000 < millis()){
// we're disabling ota after first 30sec so that nothing bad happens during playtime
is_ota_eabled = false;
Serial.println("From now on, OTA is disabled");
if (OTAPassword == nullptr) {
Serial.println("THE PASSWORD IS REQUIRED, [[ABORTING]]");
return;
}
ArduinoOTA.handle();
ArduinoOTA.setPort(OTAServerPort);
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
})
.onEnd([]() {
Serial.println("OTA updated finished successfully!");
})
.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
Serial.println("Starting up basic OTA server");
Serial.println("OTA will be live for 30s, after which it will be disabled until restart");
ArduinoOTA.begin();
bootTimestamp = millis();
}
}
void HandleOTAUpdate() {
if (isOtaEnabled) {
if (bootTimestamp + 30000 < millis()) {
// we're disabling ota after first 30sec so that nothing bad happens during playtime
isOtaEnabled = false;
Serial.println("From now on, OTA is disabled");
return;
}
ArduinoOTA.handle();
}
}
};
}

View File

@ -0,0 +1,22 @@
#pragma once
namespace OpenIris{
enum State {
Starting = 1,
ConnectingToWifi = 2,
ConnectingToWifiError = 3,
ConnectingToWifiSuccess = 4,
ServerError = 5,
CameraError = 6
};
class StateManager{
public:
StateManager() : current_state(Starting) {}
void setState(State state);
State getCurrentState();
private:
State current_state;
};
}

View File

@ -1,6 +1,9 @@
#pragma once
#include <WiFi.h>
#include "pinout.h"
namespace WiFiHandler {
void setupWifi(const char* ssid, const char* password);
namespace OpenIris {
namespace WiFiHandler {
void setupWifi(const char *ssid, const char *password);
}
}

View File

@ -1,14 +1,20 @@
#pragma once
#include "pinout.h"
#include "esp_camera.h"
#include <Arduino.h>
namespace CameraHandler{
namespace OpenIris{
class CameraHandler {
private:
sensor_t* camera_sensor;
camera_config_t config;
extern sensor_t* camera_sensor;
int setupCamera();
int setCameraResolution(framesize_t framesize);
int setVFlip(int direction);
int setHFlip(int direction);
public:
int setupCamera();
int setCameraResolution(framesize_t frameSize);
int setVFlip(int direction);
int setHFlip(int direction);
int setVieWindow(int offsetX, int offsetY, int outputX, int outputY);
};
}

View File

@ -1,9 +1,21 @@
#pragma once
#define PART_BOUNDARY "123456789000000000000987654321"
#include "esp_camera.h"
#include "esp_http_server.h"
namespace HttpdHandler{
esp_err_t stream_handler(httpd_req_t *req);
esp_err_t parse_get(httpd_req_t *req, char **obuf);
esp_err_t command_handler(httpd_req_t *req);
int startStreamServer();
namespace OpenIris{
namespace HTTPHelpers {
esp_err_t stream_handler(httpd_req_t *req);
esp_err_t parse_get(httpd_req_t *req, char **obuf);
esp_err_t command_handler(httpd_req_t *req);
}
class HTTPDHandler{
private:
httpd_handle_t camera_httpd = nullptr;
httpd_handle_t control_httpd = nullptr;
public:
int startStreamServer();
};
}

View File

@ -20,8 +20,8 @@ build_flags =
build_unflags = -Os
;upload_port = 192.168.1.43 ;replace this with your own ip
;upload_protocol = espota
upload_flags =
--auth=Password
;upload_flags =
; --auth=Password
board_build.partitions = min_spiffs.csv
lib_deps =

View File

@ -1,44 +1,24 @@
# include "LEDManager.h"
namespace LEDManager {
uint8_t ledPin = 33;
void OpenIris::LEDManager::setupLED() const {
pinMode(ledPin, OUTPUT);
}
void setupLED(){
pinMode(ledPin, OUTPUT);
off();
}
void OpenIris::LEDManager::on() const {
digitalWrite(ledPin, LOW);
void on(){
digitalWrite(ledPin, LOW);
}
}
void off(){
digitalWrite(ledPin, HIGH);
}
void OpenIris::LEDManager::off() const {
digitalWrite(ledPin, HIGH);
}
void blink(unsigned int time){
on();
delay(time);
off();
delay(time);
}
void OpenIris::LEDManager::blink(unsigned int time) {
on();
delay(time);
off();
}
void displayPattern(Status status){
if(status == Status::ConnectingToWifi){
blink(1600);
delay(1600);
}
if(status == Status::ConnectingToWifiError){
for (int i = 0; i < 5; i++){
blink(1000);
delay(1000);
}
}
if(status == Status::ConnectingToWifiSuccess){
for (int i = 0; i < 2; i++){
blink(1600);
delay(1600);
}
}
}
}
void OpenIris::LEDManager::displayStatus() {
}

11
ESP/src/StateManager.cpp Normal file
View File

@ -0,0 +1,11 @@
#include "StateManager.h"
namespace OpenIris{
void StateManager::setState(State state){
current_state=state;
}
State StateManager::getCurrentState(){
return current_state;
}
}

View File

@ -1,75 +1,83 @@
#include "cameraHandler.h"
namespace CameraHandler{
sensor_t* camera_sensor = NULL;
int setupCamera(){
Serial.print("Setting up camera \r\n");
int OpenIris::CameraHandler::setupCamera(){
Serial.print("Setting up camera \r\n");
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
if (psramFound()){
Serial.println("Found psram, setting the UXGA image quality");
config.frame_size = FRAMESIZE_240X240;
config.jpeg_quality = 10;
config.fb_count = 2;
}else{
Serial.println("Did not find psram, setting svga quality");
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
esp_err_t err = esp_camera_init(&config);
camera_sensor = esp_camera_sensor_get();
if (err != ESP_OK){
Serial.printf("Camera initialization failed with error: 0x%x \r\n", err);
return -1;
}else{
Serial.println("Sucessfully initialized the camera!");
return 0;
}
if (psramFound()){
Serial.println("Found psram, setting the 176x144 image quality");
config.frame_size = FRAMESIZE_QCIF;
config.jpeg_quality = 10;
config.fb_count = 2;
}else{
Serial.println("Did not find psram, setting svga quality");
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
int setCameraResolution(framesize_t framesize){
if(camera_sensor->pixformat == PIXFORMAT_JPEG){
try{
return camera_sensor->set_framesize(camera_sensor, framesize);
}catch(...){
// they sent us a malformed or unsupported framesize - rather than crash - tell them about it
return -1;
}
}
esp_err_t err = esp_camera_init(&config);
camera_sensor = esp_camera_sensor_get();
camera_sensor->set_special_effect(camera_sensor, 2);
if (err != ESP_OK){
Serial.printf("Camera initialization failed with error: 0x%x \r\n", err);
// TODO add led blinking here
return -1;
}else{
Serial.println("Sucessfully initialized the camera!");
// TODO add led blinking here
return 0;
}
}
int setVFlip(int direction){
return camera_sensor->set_vflip(camera_sensor, direction);
int OpenIris::CameraHandler::setCameraResolution(framesize_t frameSize){
if(camera_sensor->pixformat == PIXFORMAT_JPEG){
try{
return camera_sensor->set_framesize(camera_sensor, frameSize);
}catch(...){
// they sent us a malformed or unsupported frameSize - rather than crash - tell them about it
return -1;
}
}
return -1;
}
int setHFlip(int direction){
return camera_sensor->set_hmirror(camera_sensor, direction);
}
int OpenIris::CameraHandler::setVFlip(int direction){
return camera_sensor->set_vflip(camera_sensor, direction);
}
int OpenIris::CameraHandler::setHFlip(int direction){
return camera_sensor->set_hmirror(camera_sensor, direction);
}
int OpenIris::CameraHandler::setVieWindow(int offsetX, int offsetY, int outputX, int outputY) {
// we're only providing these parameters as these are the only ones that actually affect the ov2640
// TODO: if we're going to support different sensors - this will have to be moved to per-sensor implementation 'cause
// TODO: manufacturers handle it differently each time
// we're doubling the totalX and totalY parameters to make it easier for end user to adjust the eye ROI
// it also seems to produce a cleaner image
return camera_sensor->set_res_raw(camera_sensor, 0, 0, 0, 0, offsetX, offsetY, outputX * 2, outputY * 2, outputX, outputY, true, true);
}

View File

@ -1,177 +1,170 @@
#include <Arduino.h>
#include "cameraHandler.h"
#include "GlobalVars.h"
#include "httpdHandler.h"
#define PART_BOUNDARY "123456789000000000000987654321"
constexpr static char* STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
constexpr static char* STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
constexpr static char* STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\nX-Timestamp: %d.%06d\r\n\r\n";
namespace HttpdHandler {
httpd_handle_t camera_httpd = NULL;
httpd_handle_t control_httpd = NULL;
esp_err_t OpenIris::HTTPHelpers::stream_handler(httpd_req_t *req) {
camera_fb_t *fb = NULL;
struct timeval _timestamp;
static const char*_STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char*_STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char*_STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\nX-Timestamp: %d.%06d\r\n\r\n";
esp_err_t res = ESP_OK;
esp_err_t stream_handler(httpd_req_t *req) {
camera_fb_t *fb = NULL;
struct timeval _timestamp;
size_t _jpg_buf_len = 0;
uint8_t *_jpg_buf = NULL;
esp_err_t res = ESP_OK;
char *part_buf[128];
size_t _jpg_buf_len = 0;
uint8_t *_jpg_buf = NULL;
static int64_t last_frame = 0;
if (!last_frame)
last_frame = esp_timer_get_time();
char *part_buf[128];
static int64_t last_frame = 0;
if (!last_frame)
last_frame = esp_timer_get_time();
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if (res != ESP_OK)
return res;
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin; Content-Type: multipart/x-mixed-replace; boundary=123456789000000000000987654321\r\n", "*");
httpd_resp_set_hdr(req, "X-Framerate", "60");
while (true) {
fb = esp_camera_fb_get();
if (!fb){
ESP_LOGE(TAG, "Camera capture failed");
res = ESP_FAIL;
}
else{
_timestamp.tv_sec = fb->timestamp.tv_sec;
_timestamp.tv_usec = fb->timestamp.tv_usec;
if (fb->format != PIXFORMAT_JPEG){
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
esp_camera_fb_return(fb);
fb = NULL;
if (!jpeg_converted){
ESP_LOGE(TAG, "JPEG compression failed");
res = ESP_FAIL;
}
}
else{
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
}
if (res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if (res == ESP_OK){
size_t hlen = snprintf((char *)part_buf, 128, _STREAM_PART, _jpg_buf_len, _timestamp.tv_sec, _timestamp.tv_usec);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if (res == ESP_OK){
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if (fb){
esp_camera_fb_return(fb);
fb = NULL;
_jpg_buf = NULL;
}
else if (_jpg_buf){
free(_jpg_buf);
_jpg_buf = NULL;
}
if (res != ESP_OK){
break;
}
}
last_frame = 0;
res = httpd_resp_set_type(req, STREAM_CONTENT_TYPE);
if (res != ESP_OK)
return res;
}
esp_err_t parse_get(httpd_req_t *req, char **obuf) {
char *buf = NULL;
size_t buf_len = 0;
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin; Content-Type: multipart/x-mixed-replace; boundary=123456789000000000000987654321\r\n", "*");
httpd_resp_set_hdr(req, "X-Framerate", "60");
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1) {
buf = (char *)malloc(buf_len);
if (!buf) {
httpd_resp_send_500(req);
return ESP_FAIL;
}
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
*obuf = buf;
return ESP_OK;
}
free(buf);
while (true) {
fb = esp_camera_fb_get();
if (!fb){
ESP_LOGE(TAG, "Camera capture failed");
res = ESP_FAIL;
}
else{
_timestamp.tv_sec = fb->timestamp.tv_sec;
_timestamp.tv_usec = fb->timestamp.tv_usec;
if (fb->format != PIXFORMAT_JPEG){
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
esp_camera_fb_return(fb);
fb = NULL;
if (!jpeg_converted){
ESP_LOGE(TAG, "JPEG compression failed");
res = ESP_FAIL;
}
}
else{
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
}
if (res == ESP_OK){
res = httpd_resp_send_chunk(req, STREAM_BOUNDARY, strlen(STREAM_BOUNDARY));
}
if (res == ESP_OK){
size_t hlen = snprintf((char *)part_buf, 128, STREAM_PART, _jpg_buf_len, _timestamp.tv_sec, _timestamp.tv_usec);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if (res == ESP_OK){
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if (fb){
esp_camera_fb_return(fb);
fb = NULL;
_jpg_buf = NULL;
}
else if (_jpg_buf){
free(_jpg_buf);
_jpg_buf = NULL;
}
if (res != ESP_OK){
break;
}
}
last_frame = 0;
return res;
}
esp_err_t OpenIris::HTTPHelpers::parse_get(httpd_req_t *req, char **obuf) {
char *buf = nullptr;
size_t buf_len = 0;
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1) {
buf = (char *)malloc(buf_len);
if (!buf) {
httpd_resp_send_500(req);
return ESP_FAIL;
}
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
*obuf = buf;
return ESP_OK;
}
free(buf);
}
httpd_resp_send_404(req);
return ESP_FAIL;
}
esp_err_t OpenIris::HTTPHelpers::command_handler(httpd_req_t *req) {
char *buf = nullptr;
char variable[32];
char value[32];
if (parse_get(req, &buf) != ESP_OK)
return ESP_FAIL;
if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) != ESP_OK ||
httpd_query_key_value(buf, "val", value, sizeof(value)) != ESP_OK) {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
esp_err_t command_handler(httpd_req_t *req) {
char *buf = NULL;
char variable[32];
char value[32];
int val = atoi(value);
int res = 0;
if (!strcmp(variable, "framesize"))
res = cameraHandler.setCameraResolution((framesize_t)val);
else if (!strcmp(variable, "hmirror"))
res = cameraHandler.setHFlip(val);
else if (!strcmp(variable, "vflip"))
res = cameraHandler.setVFlip(val);
else
res = -1; // invalid command
if (parse_get(req, &buf) != ESP_OK)
return ESP_FAIL;
if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) != ESP_OK ||
httpd_query_key_value(buf, "val", value, sizeof(value)) != ESP_OK) {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
if (res < 0)
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Command not supported");
int val = atoi(value);
int res = 0;
if (!strcmp(variable, "framesize"))
res = CameraHandler::setCameraResolution((framesize_t)val);
else if (!strcmp(variable, "hmirror"))
res = CameraHandler::setHFlip(val);
else if (!strcmp(variable, "vflip"))
res = CameraHandler::setVFlip(val);
else
res = -1; // invalid command
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, nullptr, 0);
}
if (res < 0)
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Command not supported");
int OpenIris::HTTPDHandler::startStreamServer(){
Serial.println("Setting up the server");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.max_uri_handlers = 3;
int startStreamServer(){
Serial.println("Setting up the server");
httpd_uri_t control_page = {
.uri = "/control/",
.method = HTTP_GET,
.handler = &OpenIris::HTTPHelpers::command_handler,
.user_ctx = nullptr
};
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.max_uri_handlers = 3;
httpd_uri_t stream_page = {
.uri = "/",
.method = HTTP_GET,
.handler = &OpenIris::HTTPHelpers::stream_handler,
.user_ctx = nullptr
};
httpd_uri_t control_page = {
.uri = "/control/",
.method = HTTP_GET,
.handler = &command_handler,
.user_ctx = NULL
};
int streamer_status = httpd_start(&control_httpd, &config);
httpd_uri_t stream_page = {
.uri = "/",
.method = HTTP_GET,
.handler = &stream_handler,
.user_ctx = NULL
};
config.server_port += 1;
config.ctrl_port += 1;
int streamer_status = httpd_start(&control_httpd, &config);
config.server_port += 1;
config.ctrl_port += 1;
int cmd_controller_status = httpd_start(&camera_httpd, &config);
int cmd_controller_status = httpd_start(&camera_httpd, &config);
if (streamer_status != ESP_OK || cmd_controller_status != ESP_OK)
return -1;
else {
httpd_register_uri_handler(control_httpd, &control_page);
httpd_register_uri_handler(camera_httpd, &stream_page);
Serial.println("Server is ready to serve!");
return 0;
}
if (streamer_status != ESP_OK || cmd_controller_status != ESP_OK)
return -1;
else {
httpd_register_uri_handler(control_httpd, &control_page);
httpd_register_uri_handler(camera_httpd, &stream_page);
Serial.println("Server is ready to serve!");
return 0;
}
}

View File

@ -6,24 +6,29 @@
#include "LEDManager.h"
#include "httpdHandler.h"
#include "OTA.h"
#include "StateManager.h"
auto ota = OpenIris::OTA();
auto ledManager = OpenIris::LEDManager(33);
auto cameraHandler = OpenIris::CameraHandler();
auto stateManager = OpenIris::StateManager();
auto httpdHandler = OpenIris::HTTPDHandler();
void setup(){
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
Serial.println("setting up led");
LEDManager::setupLED();
// todo add blink handling
CameraHandler::setupCamera();
WiFiHandler::setupWifi(ssid, password);
// todo add blink handling
HttpdHandler::startStreamServer();
LEDManager::on();
OTA::SetupOTA(OTAPassword, OTAServerPort);
ledManager.setupLED();
cameraHandler.setupCamera();
OpenIris::WiFiHandler::setupWifi(ssid, password);
httpdHandler.startStreamServer();
ledManager.on();
ota.SetupOTA(OTAPassword, OTAServerPort);
}
void loop(){
OTA::HandleOTAUpdate();
ota.HandleOTAUpdate();
ledManager.displayStatus();
}

View File

@ -1,39 +1,37 @@
#include "WifiHandler.h"
#include "LEDManager.h"
#include "GlobalVars.h"
namespace WiFiHandler {
void setupWifi(const char* ssid, const char* password){
Serial.println("Initializing connection to wifi");
void OpenIris::WiFiHandler::setupWifi(const char* ssid, const char* password){
Serial.println("Initializing connection to wifi");
WiFi.begin(ssid, password);
WiFi.begin(ssid, password);
Serial.print("connecting");
int time_spent_connecting = 0;
int connection_timeout = 6400;
int wifi_status = WiFi.status();
Serial.print("connecting");
int time_spent_connecting = 0;
int connection_timeout = 6400;
int wifi_status = WiFi.status();
while (time_spent_connecting < connection_timeout || wifi_status != WL_CONNECTED){
wifi_status = WiFi.status();
Serial.print(".");
LEDManager::blink(LEDManager::Status::ConnectingToWifi);
time_spent_connecting += 1600;
delay(1600);
}
if(wifi_status == WL_CONNECTED){
LEDManager::blink(LEDManager::Status::ConnectingToWifiSuccess);
delay(1600);
Serial.print("\n\rWiFi connected\n\r");
Serial.print("ESP will be streaming under 'http://");
Serial.print(WiFi.localIP());
Serial.print(":81/\r\n");
Serial.print("ESP will be accepting commands under 'http://");
Serial.print(WiFi.localIP());
Serial.print(":80/control\r\n");
}
else{
LEDManager::blink(LEDManager::Status::ConnectingToWifiError);
return;
}
while (time_spent_connecting < connection_timeout || wifi_status != WL_CONNECTED){
wifi_status = WiFi.status();
Serial.print(".");
stateManager.setState(OpenIris::State::ConnectingToWifi);
time_spent_connecting += 1600;
delay(1600);
}
}
if(wifi_status == WL_CONNECTED){
stateManager.setState(OpenIris::State::ConnectingToWifiSuccess);
delay(1600);
Serial.print("\n\rWiFi connected\n\r");
Serial.print("ESP will be streaming under 'http://");
Serial.print(WiFi.localIP());
Serial.print(":81/\r\n");
Serial.print("ESP will be accepting commands under 'http://");
Serial.print(WiFi.localIP());
Serial.print(":80/control\r\n");
}
else{
stateManager.setState(OpenIris::State::ConnectingToWifiError);
return;
}
}

46
main.py
View File

@ -1,46 +0,0 @@
import cv2 as cv
import threading
import numpy as np
class ThreadedCamera:
def __init__(self, camera_index=0):
self.cam = cv.VideoCapture(camera_index)
self.status = False
self.frame = None
if not self.cam.isOpened():
raise Exception("Could not connect to a camera")
self.cam.set(cv.CAP_PROP_BUFFERSIZE, 3)
self.camera_thread = threading.Thread(target=self.update, args=(), daemon=True)
self.camera_thread.start()
def update(self):
while True:
ret, frame = self.cam.read()
if not ret:
print("something went wrong with reading frame, exiting")
break
self.status, self.frame = ret, frame
def display_frame(self):
if self.frame is not None:
image = cv.cvtColor(self.frame, cv.COLOR_BGR2GRAY)
image = cv.resize(image, dsize=(int(self.frame.shape[1]/3), int(self.frame.shape[0]/3)))
cv.imshow("frame", image)
fps = self.cam.get(cv.CAP_PROP_FPS)
print("Frames per second using video.get(cv2.CAP_PROP_FPS) : {0}".format(fps))
if cv.waitKey(1) == ord("q"):
exit()
def main():
camera = ThreadedCamera(0)
while True:
camera.display_frame()
if __name__ == "__main__":
main()