Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
c9dc770880 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,4 +3,3 @@
|
|||||||
.vscode/c_cpp_properties.json
|
.vscode/c_cpp_properties.json
|
||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
.vscode/ipch
|
.vscode/ipch
|
||||||
test/build/*
|
|
||||||
|
@ -21,4 +21,3 @@ lib_deps =
|
|||||||
arduino-libraries/Ethernet@^2.0.2
|
arduino-libraries/Ethernet@^2.0.2
|
||||||
paulstoffregen/Time@^1.6.1
|
paulstoffregen/Time@^1.6.1
|
||||||
bblanchon/ArduinoJson@^6.21.3
|
bblanchon/ArduinoJson@^6.21.3
|
||||||
google/googletest@^1.12.1
|
|
||||||
|
@ -27,4 +27,3 @@
|
|||||||
// make it configurable with some panel
|
// make it configurable with some panel
|
||||||
//#define NOISE_THRESHOLD 3000000
|
//#define NOISE_THRESHOLD 3000000
|
||||||
#define NOISE_THRESHOLD 10000000
|
#define NOISE_THRESHOLD 10000000
|
||||||
//#define NOISE_THRESHOLD 20000000
|
|
@ -1,125 +0,0 @@
|
|||||||
#include "domain/AidStrategy.h"
|
|
||||||
|
|
||||||
#include "utils/Time.h"
|
|
||||||
#include "config/config.h"
|
|
||||||
|
|
||||||
void AidStrategy::setup() {
|
|
||||||
_task1_mutex = xSemaphoreCreateMutex();
|
|
||||||
_task2_mutex = xSemaphoreCreateMutex();
|
|
||||||
_http_mutex = xSemaphoreCreateMutex();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AidStrategy::process() {
|
|
||||||
xTaskCreatePinnedToCore(processTask, "ProcessTask1", 4096, this, 1, NULL, 0);
|
|
||||||
//xTaskCreatePinnedToCore(processTask, "ProcessTask2", 4096, this, 1, NULL, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AidStrategy::processTask(void* parameters) {
|
|
||||||
AidStrategy* aidStrategy = static_cast<AidStrategy*>(parameters);
|
|
||||||
Audio* audioSource =
|
|
||||||
(xTaskGetAffinity(NULL) == 0) ? aidStrategy->_audio : aidStrategy->_audio1;
|
|
||||||
|
|
||||||
aidStrategy->_writeToPrecedingBuffer(audioSource);
|
|
||||||
|
|
||||||
if (aidStrategy->_isNoiseDetected(audioSource)) {
|
|
||||||
aidStrategy->_recordAudio(audioSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
vTaskDelete(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AidStrategy::_writeToPrecedingBuffer(Audio* audioSource) {
|
|
||||||
if (!_isWritingToPrecedingBuffer && !_recordingAudio) {
|
|
||||||
_isWritingToPrecedingBuffer = true;
|
|
||||||
audioSource->writeToPrecedingBuffer();
|
|
||||||
_isWritingToPrecedingBuffer = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AidStrategy::_isNoiseDetected(Audio* audioSource) {
|
|
||||||
return audioSource->isNoiseDetected();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AidStrategy::_recordAudio(Audio* audioSource) {
|
|
||||||
if (_recordingAudio)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Serial.println("!!!");
|
|
||||||
|
|
||||||
bool isReady = false;
|
|
||||||
_recordingAudio = true;
|
|
||||||
|
|
||||||
if (xSemaphoreTake(_http_mutex, portMAX_DELAY)) {
|
|
||||||
isReady = _ready();
|
|
||||||
xSemaphoreGive(_http_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isReady) {
|
|
||||||
Serial.println("========================================");
|
|
||||||
Serial.println("| RECORDING...");
|
|
||||||
audioSource->record();
|
|
||||||
Serial.println("| Recording finished");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xSemaphoreTake(_http_mutex, portMAX_DELAY)) {
|
|
||||||
if (_http->connect(RAT_IP, RAT_PORT)) {
|
|
||||||
_sendAudio(audioSource);
|
|
||||||
_http->stop();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Serial.println("| Connection failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
xSemaphoreGive(_http_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
_recordingAudio = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String AidStrategy::_ready() {
|
|
||||||
return _http->send("POST", "/aid/ready", RAT_IP, RAT_PORT, "", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
void AidStrategy::_sendAudio(Audio* audioSource) {
|
|
||||||
String payloadStart = _formPayloadStart(_audio->getStartMicros());
|
|
||||||
String payloadEnd = _formPayloadEnd();
|
|
||||||
|
|
||||||
int audioLength = _audio->getSize();
|
|
||||||
int jsonLength = payloadStart.length() + audioLength + payloadEnd.length();
|
|
||||||
|
|
||||||
_http->printHeader("POST", "/aid/save", RAT_IP, "application/json");
|
|
||||||
_http->printContentLength(jsonLength);
|
|
||||||
|
|
||||||
this->_printContent(payloadStart, payloadEnd, _http->getClient());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AidStrategy::_printContent(String payloadStart, String payloadEnd, Stream* stream) {
|
|
||||||
stream->print(payloadStart);
|
|
||||||
_audio->print(stream);
|
|
||||||
stream->print(payloadEnd);
|
|
||||||
|
|
||||||
_logContent(payloadStart, payloadEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AidStrategy::_logContent(String payloadStart, String payloadEnd) {
|
|
||||||
Serial.print("| ");
|
|
||||||
Serial.print(payloadStart);
|
|
||||||
Serial.print("...");
|
|
||||||
Serial.print(payloadEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
String AidStrategy::_formPayloadStart(unsigned long startMicros) {
|
|
||||||
String payloadStart = "";
|
|
||||||
|
|
||||||
payloadStart += "{\"audio\":{\"micros\":";
|
|
||||||
payloadStart += String(_audio->getStartMicros() - _timeModule.getInitialMicros());
|
|
||||||
payloadStart += ",\"initialTime\":";
|
|
||||||
payloadStart += String(_timeModule.getInitialTime());
|
|
||||||
payloadStart += ",\"content\":\"";
|
|
||||||
|
|
||||||
return payloadStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
String AidStrategy::_formPayloadEnd() {
|
|
||||||
return "\"}}\r\n\r\n";
|
|
||||||
}
|
|
@ -1,104 +0,0 @@
|
|||||||
#include "domain/AidStrategy.h"
|
|
||||||
|
|
||||||
#include "utils/Time.h"
|
|
||||||
#include "config/config.h"
|
|
||||||
|
|
||||||
void AidStrategy::setup() {}
|
|
||||||
|
|
||||||
void AidStrategy::process() {
|
|
||||||
_writeToPrecedingBuffer(_audio);
|
|
||||||
|
|
||||||
if (_isNoiseDetected(_audio)) {
|
|
||||||
_recordAudio(_audio);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AidStrategy::_writeToPrecedingBuffer(Audio* audioSource) {
|
|
||||||
if (!_isWritingToPrecedingBuffer && !_recordingAudio) {
|
|
||||||
_isWritingToPrecedingBuffer = true;
|
|
||||||
audioSource->writeToPrecedingBuffer();
|
|
||||||
_isWritingToPrecedingBuffer = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AidStrategy::_isNoiseDetected(Audio* audioSource) {
|
|
||||||
return audioSource->isNoiseDetected();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AidStrategy::_recordAudio(Audio* audioSource) {
|
|
||||||
if (_recordingAudio)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Serial.println("!!!");
|
|
||||||
|
|
||||||
bool isReady = false;
|
|
||||||
_recordingAudio = true;
|
|
||||||
|
|
||||||
isReady = _ready();
|
|
||||||
|
|
||||||
if (!isReady)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_http->connect(RAT_IP, RAT_PORT)) {
|
|
||||||
Serial.println("========================================");
|
|
||||||
Serial.println("| RECORDING...");
|
|
||||||
audioSource->record();
|
|
||||||
Serial.println("| Recording finished");
|
|
||||||
|
|
||||||
_sendAudio(audioSource);
|
|
||||||
_http->stop();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Serial.println("| Connection failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
_recordingAudio = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String AidStrategy::_ready() {
|
|
||||||
return _http->send("POST", "/aid/ready", RAT_IP, RAT_PORT, "", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
void AidStrategy::_sendAudio(Audio* audioSource) {
|
|
||||||
String payloadStart = _formPayloadStart(_audio->getStartMicros());
|
|
||||||
String payloadEnd = _formPayloadEnd();
|
|
||||||
|
|
||||||
int audioLength = _audio->getSize();
|
|
||||||
int jsonLength = payloadStart.length() + audioLength + payloadEnd.length();
|
|
||||||
|
|
||||||
_http->printHeader("POST", "/aid/save", RAT_IP, "application/json");
|
|
||||||
_http->printContentLength(jsonLength);
|
|
||||||
|
|
||||||
this->_printContent(payloadStart, payloadEnd, _http->getClient());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AidStrategy::_printContent(String payloadStart, String payloadEnd, Stream* stream) {
|
|
||||||
stream->print(payloadStart);
|
|
||||||
_audio->print(stream);
|
|
||||||
stream->print(payloadEnd);
|
|
||||||
|
|
||||||
_logContent(payloadStart, payloadEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AidStrategy::_logContent(String payloadStart, String payloadEnd) {
|
|
||||||
Serial.print("| ");
|
|
||||||
Serial.print(payloadStart);
|
|
||||||
Serial.print("...");
|
|
||||||
Serial.print(payloadEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
String AidStrategy::_formPayloadStart(unsigned long startMicros) {
|
|
||||||
String payloadStart = "";
|
|
||||||
|
|
||||||
payloadStart += "{\"audio\":{\"micros\":";
|
|
||||||
payloadStart += String(_audio->getStartMicros() - _timeModule.getInitialMicros());
|
|
||||||
payloadStart += ",\"initialTime\":";
|
|
||||||
payloadStart += String(_timeModule.getInitialTime());
|
|
||||||
payloadStart += ",\"content\":\"";
|
|
||||||
|
|
||||||
return payloadStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
String AidStrategy::_formPayloadEnd() {
|
|
||||||
return "\"}}\r\n\r\n";
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "domain/BaseStrategy.h"
|
|
||||||
|
|
||||||
#include "utils/Time.h"
|
|
||||||
|
|
||||||
class AidStrategy : public BaseStrategy {
|
|
||||||
private:
|
|
||||||
Time& _timeModule = Time::getInstance();
|
|
||||||
SemaphoreHandle_t _task1_mutex;
|
|
||||||
SemaphoreHandle_t _task2_mutex;
|
|
||||||
SemaphoreHandle_t _http_mutex;
|
|
||||||
|
|
||||||
bool _isWritingToPrecedingBuffer = false;
|
|
||||||
bool _recordingAudio = false;
|
|
||||||
|
|
||||||
void _recordAudio(Audio* audioSource);
|
|
||||||
void _writeToPrecedingBuffer(Audio* audioSource);
|
|
||||||
bool _isNoiseDetected(Audio* audioSource);
|
|
||||||
|
|
||||||
String _ready();
|
|
||||||
void _sendAudio(Audio* audioSource);
|
|
||||||
void _printContent(String payloadStart, String payloadEnd, Stream* stream);
|
|
||||||
void _logContent(String payloadStart, String payloadEnd);
|
|
||||||
|
|
||||||
String _formPayloadStart(unsigned long startMicros);
|
|
||||||
String _formPayloadEnd();
|
|
||||||
|
|
||||||
static void processTask(void* parameters);
|
|
||||||
|
|
||||||
public:
|
|
||||||
AidStrategy(MicType micType, Http* http) : BaseStrategy(micType, http) {}
|
|
||||||
~AidStrategy() {}
|
|
||||||
|
|
||||||
void setup();
|
|
||||||
void process();
|
|
||||||
};
|
|
@ -1,37 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "infra/Audio.h"
|
|
||||||
#include "infra/Http.h"
|
|
||||||
|
|
||||||
class BaseStrategy {
|
|
||||||
protected:
|
|
||||||
Audio* _audio;
|
|
||||||
Audio* _audio1;
|
|
||||||
Http* _http;
|
|
||||||
|
|
||||||
public:
|
|
||||||
BaseStrategy(MicType micType, Http* http) {
|
|
||||||
Serial.print("Free heap: ");
|
|
||||||
Serial.println(esp_get_minimum_free_heap_size());
|
|
||||||
|
|
||||||
_audio = new Audio(micType, I2S_NUM_0);
|
|
||||||
|
|
||||||
Serial.print("Free heap: ");
|
|
||||||
Serial.println(esp_get_minimum_free_heap_size());
|
|
||||||
|
|
||||||
_audio1 = new Audio(micType, I2S_NUM_1);
|
|
||||||
|
|
||||||
Serial.print("Free heap: ");
|
|
||||||
Serial.println(esp_get_minimum_free_heap_size());
|
|
||||||
|
|
||||||
_http = http;
|
|
||||||
}
|
|
||||||
|
|
||||||
~BaseStrategy() {
|
|
||||||
delete _audio;
|
|
||||||
delete _audio1;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void setup() = 0;
|
|
||||||
virtual void process() = 0;
|
|
||||||
};
|
|
@ -1,30 +0,0 @@
|
|||||||
|
|
||||||
#include "domain/Controller.h"
|
|
||||||
|
|
||||||
Controller Controller::_instance;
|
|
||||||
Controller::Controller() : _strategy(nullptr) {}
|
|
||||||
|
|
||||||
void Controller::setStrategy(BaseStrategy* newStrategy) {
|
|
||||||
if (_strategy) {
|
|
||||||
delete _strategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
_strategy = newStrategy;
|
|
||||||
if (_strategy) {
|
|
||||||
_strategy->setup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller::~Controller() {
|
|
||||||
if (_strategy) {
|
|
||||||
delete _strategy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller& Controller::getInstance() {
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::process() {
|
|
||||||
_strategy->process();
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
#include "domain/BaseStrategy.h"
|
|
||||||
|
|
||||||
class Controller {
|
|
||||||
private:
|
|
||||||
static Controller _instance;
|
|
||||||
BaseStrategy* _strategy;
|
|
||||||
|
|
||||||
Controller();
|
|
||||||
Controller(Controller const&) = delete;
|
|
||||||
void operator=(Controller const&) = delete;
|
|
||||||
~Controller();
|
|
||||||
|
|
||||||
public:
|
|
||||||
static Controller& getInstance();
|
|
||||||
void setStrategy(BaseStrategy* strategy);
|
|
||||||
void process();
|
|
||||||
};
|
|
83
src/domain/Recorder.cpp
Normal file
83
src/domain/Recorder.cpp
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#include "domain/Recorder.h"
|
||||||
|
|
||||||
|
#include "config/config.h"
|
||||||
|
#include "utils/Time.h"
|
||||||
|
|
||||||
|
Time& timeModule = Time::getInstance();
|
||||||
|
|
||||||
|
Recorder::Recorder(MicType micType, Http* http) {
|
||||||
|
_audio = new Audio(micType);
|
||||||
|
_http = http;
|
||||||
|
}
|
||||||
|
|
||||||
|
Recorder::~Recorder() {
|
||||||
|
delete _audio;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Recorder::recordAudio() {
|
||||||
|
_ready();
|
||||||
|
|
||||||
|
if (_http->connect(RAT_IP, RAT_PORT)) {
|
||||||
|
Serial.println("========================================");
|
||||||
|
Serial.println("| RECORDING...");
|
||||||
|
_audio->record();
|
||||||
|
Serial.println("| Recording finished");
|
||||||
|
|
||||||
|
_transcribe();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Serial.println("| Connection failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Recorder::_ready() {
|
||||||
|
_http->send("POST", "/ready", RAT_IP, RAT_PORT, "", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Recorder::_transcribe() {
|
||||||
|
String payloadStart = _formPayloadStart();
|
||||||
|
String payloadEnd = _formPayloadEnd();
|
||||||
|
|
||||||
|
int audioLength = _audio->getSize();
|
||||||
|
int jsonLength = payloadStart.length() + audioLength + payloadEnd.length();
|
||||||
|
|
||||||
|
_http->printHeader("POST", "/save_to_file", RAT_IP, "application/json");
|
||||||
|
_http->printContentLength(jsonLength);
|
||||||
|
|
||||||
|
this->_printContent(payloadStart, payloadEnd, _http->getClient());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Recorder::_printContent(String payloadStart, String payloadEnd, Stream* stream) {
|
||||||
|
stream->print(payloadStart);
|
||||||
|
_audio->print(stream);
|
||||||
|
stream->print(payloadEnd);
|
||||||
|
|
||||||
|
_logContent(payloadStart, payloadEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Recorder::_logContent(String payloadStart, String payloadEnd) {
|
||||||
|
Serial.print("| ");
|
||||||
|
Serial.print(payloadStart);
|
||||||
|
Serial.print("...");
|
||||||
|
Serial.print(payloadEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
String Recorder::_formPayloadStart() {
|
||||||
|
String payloadStart = "";
|
||||||
|
|
||||||
|
payloadStart += "{\"audio\":{\"micros\":";
|
||||||
|
payloadStart += String(_audio->getStartMicros() - timeModule.getInitialMicros());
|
||||||
|
payloadStart += ",\"initialTime\":";
|
||||||
|
payloadStart += String(timeModule.getInitialTime());
|
||||||
|
payloadStart += ",\"content\":\"";
|
||||||
|
|
||||||
|
return payloadStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Recorder::_formPayloadEnd() {
|
||||||
|
return "\"}}\r\n\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Recorder::isNoiseDetected(int threshold) {
|
||||||
|
return _audio->isNoiseDetected(threshold);
|
||||||
|
}
|
25
src/domain/Recorder.h
Normal file
25
src/domain/Recorder.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "infra/Audio.h"
|
||||||
|
#include "infra/Http.h"
|
||||||
|
|
||||||
|
class Recorder {
|
||||||
|
private:
|
||||||
|
Audio* _audio;
|
||||||
|
Http* _http;
|
||||||
|
|
||||||
|
void _ready();
|
||||||
|
void _transcribe();
|
||||||
|
void _printContent(String payloadStart, String payloadEnd, Stream* stream);
|
||||||
|
void _logContent(String payloadStart, String payloadEnd);
|
||||||
|
void _printAudio();
|
||||||
|
|
||||||
|
String _formPayloadStart();
|
||||||
|
String _formPayloadEnd();
|
||||||
|
|
||||||
|
public:
|
||||||
|
Recorder(MicType micType, Http* http);
|
||||||
|
~Recorder();
|
||||||
|
void recordAudio();
|
||||||
|
bool isNoiseDetected(int threshold);
|
||||||
|
};
|
@ -1,13 +0,0 @@
|
|||||||
#include "domain/RecorderStrategy.h"
|
|
||||||
|
|
||||||
#include "config/config.h"
|
|
||||||
|
|
||||||
void RecorderStrategy::setup() {}
|
|
||||||
|
|
||||||
void RecorderStrategy::process() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void RecorderStrategy::_check() {
|
|
||||||
_http->send("POST", "/recorder/check", RAT_IP, RAT_PORT, "", "");
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "domain/BaseStrategy.h"
|
|
||||||
|
|
||||||
#include "utils/Time.h"
|
|
||||||
|
|
||||||
class RecorderStrategy : public BaseStrategy {
|
|
||||||
private:
|
|
||||||
Time& _timeModule = Time::getInstance();
|
|
||||||
|
|
||||||
void _check();
|
|
||||||
|
|
||||||
public:
|
|
||||||
void setup();
|
|
||||||
void process();
|
|
||||||
};
|
|
@ -1,26 +1,17 @@
|
|||||||
#include "infra/Audio.h"
|
#include "infra/Audio.h"
|
||||||
|
|
||||||
#include <base64.h>
|
#include <base64.h>
|
||||||
#include "config/config.h"
|
|
||||||
|
|
||||||
#define PRECEDING_BUFFER_SIZE 4
|
Audio::Audio(MicType micType) {
|
||||||
|
|
||||||
Audio::Audio(MicType micType, i2s_port_t i2sNum) {
|
|
||||||
_wavData = new char*[_wavDataSize/_dividedWavDataSize];
|
_wavData = new char*[_wavDataSize/_dividedWavDataSize];
|
||||||
for (int i = 0; i < _wavDataSize/_dividedWavDataSize; ++i)
|
for (int i = 0; i < _wavDataSize/_dividedWavDataSize; ++i) _wavData[i] = new char[_dividedWavDataSize];
|
||||||
_wavData[i] = new char[_dividedWavDataSize];
|
i2s = new I2S(micType);
|
||||||
|
|
||||||
_precedingWavBuffer = new CircularBuffer<char*>(_precedingWavPartsAmount);
|
|
||||||
|
|
||||||
i2s = new I2S(micType, i2sNum);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Audio::~Audio() {
|
Audio::~Audio() {
|
||||||
for (int i = 0; i < _wavDataSize/_dividedWavDataSize; ++i) delete[] _wavData[i];
|
for (int i = 0; i < _wavDataSize/_dividedWavDataSize; ++i) delete[] _wavData[i];
|
||||||
delete[] _wavData;
|
delete[] _wavData;
|
||||||
delete i2s;
|
delete i2s;
|
||||||
|
|
||||||
emptyPrecedingBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::_createWavHeader(byte* header, int waveDataSize){
|
void Audio::_createWavHeader(byte* header, int waveDataSize){
|
||||||
@ -47,7 +38,7 @@ void Audio::_createWavHeader(byte* header, int waveDataSize){
|
|||||||
header[19] = 0x00;
|
header[19] = 0x00;
|
||||||
header[20] = 0x01; // linear PCM
|
header[20] = 0x01; // linear PCM
|
||||||
header[21] = 0x00;
|
header[21] = 0x00;
|
||||||
header[22] = 0x02; // stereo
|
header[22] = 0x01; // monoral
|
||||||
header[23] = 0x00;
|
header[23] = 0x00;
|
||||||
header[24] = 0x80; // sampling rate 16000
|
header[24] = 0x80; // sampling rate 16000
|
||||||
header[25] = 0x3E;
|
header[25] = 0x3E;
|
||||||
@ -72,78 +63,30 @@ void Audio::_createWavHeader(byte* header, int waveDataSize){
|
|||||||
}
|
}
|
||||||
|
|
||||||
char** Audio::record() {
|
char** Audio::record() {
|
||||||
_noiseDetectedInPrecedingBuffer = false;
|
|
||||||
|
|
||||||
_createWavHeader(_paddedHeader, _wavDataSize);
|
_createWavHeader(_paddedHeader, _wavDataSize);
|
||||||
|
|
||||||
_startMicros = micros();
|
|
||||||
_readFromPrecedingBuffer(_wavData);
|
|
||||||
_recordToBuffer(_wavData + _precedingWavPartsAmount, _wavDataSize - _precedingWavDataSize);
|
|
||||||
|
|
||||||
return _wavData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Audio::_recordToBuffer(char** wavBuffer, int waveDataSize) {
|
|
||||||
int bitBitPerSample = i2s->GetBitPerSample();
|
int bitBitPerSample = i2s->GetBitPerSample();
|
||||||
|
|
||||||
|
_startMicros = micros();
|
||||||
|
|
||||||
if (bitBitPerSample == 16) {
|
if (bitBitPerSample == 16) {
|
||||||
for (int j = 0; j < waveDataSize / _dividedWavDataSize; ++j) {
|
for (int j = 0; j < _wavDataSize/_dividedWavDataSize; ++j) {
|
||||||
i2s->Read(_i2sBuffer, _i2sBufferSize/2);
|
i2s->Read(_i2sBuffer, _i2sBufferSize/2);
|
||||||
_convertBufferToWav(wavBuffer[j]);
|
for (int i = 0; i < _i2sBufferSize/8; ++i) {
|
||||||
|
_wavData[j][2*i] = _i2sBuffer[4*i + 2];
|
||||||
|
_wavData[j][2*i + 1] = _i2sBuffer[4*i + 3];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (bitBitPerSample == 32) {
|
else if (bitBitPerSample == 32) {
|
||||||
for (int j = 0; j < waveDataSize / _dividedWavDataSize; ++j) {
|
for (int j = 0; j < _wavDataSize/_dividedWavDataSize; ++j) {
|
||||||
i2s->Read(_i2sBuffer, _i2sBufferSize);
|
i2s->Read(_i2sBuffer, _i2sBufferSize);
|
||||||
for (int i = 0; i < _i2sBufferSize/8; ++i) {
|
for (int i = 0; i < _i2sBufferSize/8; ++i) {
|
||||||
wavBuffer[j][2*i] = _i2sBuffer[8*i + 2] << 4; // TODO: check << 4 in 16bit
|
_wavData[j][2*i] = _i2sBuffer[8*i + 2] << 4;
|
||||||
wavBuffer[j][2*i + 1] = _i2sBuffer[8*i + 3] << 4;
|
_wavData[j][2*i + 1] = _i2sBuffer[8*i + 3] << 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return _wavData;
|
||||||
|
|
||||||
void Audio::_readFromPrecedingBuffer(char** wavBuffer) {
|
|
||||||
for (int i = 0; i < _precedingWavPartsAmount; i++) {
|
|
||||||
if (!_precedingWavBuffer->isEmpty()) {
|
|
||||||
char* tmp;
|
|
||||||
_precedingWavBuffer->popFront(tmp);
|
|
||||||
delete wavBuffer[i];
|
|
||||||
wavBuffer[i] = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emptyPrecedingBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Audio::emptyPrecedingBuffer() {
|
|
||||||
while (!_precedingWavBuffer->isEmpty()) {
|
|
||||||
char* tmp;
|
|
||||||
_precedingWavBuffer->popFront(tmp);
|
|
||||||
delete tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Audio::writeToPrecedingBuffer() {
|
|
||||||
if (_precedingWavBuffer->isFull()) {
|
|
||||||
char* tmp;
|
|
||||||
_precedingWavBuffer->popFront(tmp);
|
|
||||||
delete tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
i2s->Read(_i2sBuffer, _i2sBufferSize/2);
|
|
||||||
_noiseDetectedInPrecedingBuffer = _isNoiseDetectedInPrecedingBuffer();
|
|
||||||
|
|
||||||
char* _partialWavBuffer = new char[_dividedWavDataSize];
|
|
||||||
_convertBufferToWav(_partialWavBuffer);
|
|
||||||
|
|
||||||
CircularBufferErrorCode err = _precedingWavBuffer->pushBack(_partialWavBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Audio::_convertBufferToWav(char* partialWavBuffer) {
|
|
||||||
for (int i = 0; i < _i2sBufferSize/2; ++i) {
|
|
||||||
partialWavBuffer[i] = _i2sBuffer[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Audio::getSize() {
|
int Audio::getSize() {
|
||||||
@ -151,30 +94,12 @@ int Audio::getSize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String Audio::print(Stream* stream) {
|
String Audio::print(Stream* stream) {
|
||||||
return printHeader(stream) + printContent(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
String Audio::printHeader(Stream* stream) {
|
|
||||||
String enc = base64::encode(_paddedHeader, sizeof(_paddedHeader));
|
String enc = base64::encode(_paddedHeader, sizeof(_paddedHeader));
|
||||||
enc.replace("\n", "");
|
enc.replace("\n", "");
|
||||||
stream->print(enc);
|
stream->print(enc);
|
||||||
|
|
||||||
return enc;
|
|
||||||
}
|
|
||||||
|
|
||||||
String Audio::printContent(Stream* stream) {
|
|
||||||
String enc;
|
|
||||||
|
|
||||||
Serial.print("Free heap: ");
|
|
||||||
Serial.println(esp_get_minimum_free_heap_size());
|
|
||||||
|
|
||||||
for (int j = 0; j < _wavDataSize / _dividedWavDataSize; ++j) {
|
for (int j = 0; j < _wavDataSize / _dividedWavDataSize; ++j) {
|
||||||
enc = base64::encode((byte*)_wavData[j], _dividedWavDataSize/2);
|
enc = base64::encode((byte*)_wavData[j], _dividedWavDataSize);
|
||||||
enc.replace("\n", "");
|
|
||||||
stream->print(enc);
|
|
||||||
|
|
||||||
enc = base64::encode((byte*)_wavData[j] + _dividedWavDataSize/2,
|
|
||||||
_dividedWavDataSize/2);
|
|
||||||
enc.replace("\n", "");
|
enc.replace("\n", "");
|
||||||
stream->print(enc);
|
stream->print(enc);
|
||||||
}
|
}
|
||||||
@ -186,15 +111,13 @@ unsigned long Audio::getStartMicros() {
|
|||||||
return _startMicros;
|
return _startMicros;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Audio::_isNoiseDetectedInPrecedingBuffer() {
|
bool Audio::isNoiseDetected(int threshold) {
|
||||||
if (*(int*)_i2sBuffer > NOISE_THRESHOLD || *(int*)_i2sBuffer < -NOISE_THRESHOLD) {
|
i2s->Read(_i2sBuffer2, _i2sBufferSize/2);
|
||||||
Serial.println("Noise detected");
|
if (*(int*)_i2sBuffer2 > threshold || *(int*)_i2sBuffer2 < -threshold) {
|
||||||
|
Serial.print(*(int*)_i2sBuffer2);
|
||||||
|
Serial.print(" ");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Audio::isNoiseDetected() {
|
|
||||||
return _noiseDetectedInPrecedingBuffer;
|
|
||||||
}
|
|
@ -3,52 +3,34 @@
|
|||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#include "libs/CircularBuffer.h"
|
|
||||||
#include "infra/I2S.h"
|
#include "infra/I2S.h"
|
||||||
|
|
||||||
// 16bit, monoral, 16000Hz, linear PCM
|
// 16bit, monoral, 16000Hz, linear PCM
|
||||||
class Audio {
|
class Audio {
|
||||||
private:
|
private:
|
||||||
I2S* i2s;
|
I2S* i2s;
|
||||||
|
|
||||||
static const int _headerSize = 44;
|
static const int _headerSize = 44;
|
||||||
static const int _i2sBufferSize = 6048/2;
|
static const int _i2sBufferSize = 6000;
|
||||||
char _i2sBuffer[_i2sBufferSize/2];
|
char _i2sBuffer[_i2sBufferSize];
|
||||||
|
char _i2sBuffer2[_i2sBufferSize];
|
||||||
|
|
||||||
static const int _wavDataSize = 90720/2; // It must be multiple of _dividedWavDataSize. Recording time is about 1.9 second.
|
static const int _wavDataSize = 90000; // It must be multiple of _dividedWavDataSize. Recording time is about 1.9 second.
|
||||||
static const int _dividedWavDataSize = _i2sBufferSize/2;
|
static const int _dividedWavDataSize = _i2sBufferSize/4;
|
||||||
char** _wavData; // It's divided. Because large continuous memory area can't be allocated in esp32.
|
char** _wavData; // It's divided. Because large continuous memory area can't be allocated in esp32.
|
||||||
|
|
||||||
static const int _precedingWavPartsAmount = (_wavDataSize/_dividedWavDataSize)/5;
|
|
||||||
static const int _precedingWavDataSize =
|
|
||||||
_precedingWavPartsAmount*_dividedWavDataSize;
|
|
||||||
char** _precedingWavData;
|
|
||||||
CircularBuffer<char*>* _precedingWavBuffer;
|
|
||||||
bool _precedingBufferFull = false;
|
|
||||||
bool _noiseDetectedInPrecedingBuffer = false;
|
|
||||||
|
|
||||||
byte _paddedHeader[_headerSize + 4] = {0}; // The size must be multiple of 3 for Base64 encoding. Additional byte size must be even because wave data is 16bit.
|
byte _paddedHeader[_headerSize + 4] = {0}; // The size must be multiple of 3 for Base64 encoding. Additional byte size must be even because wave data is 16bit.
|
||||||
|
|
||||||
unsigned long _startMicros = 0;
|
unsigned long _startMicros = 0;
|
||||||
|
|
||||||
void _recordToBuffer(char** wavBuffer, int waveDataSize);
|
|
||||||
void _readFromPrecedingBuffer(char** wavBuffer);
|
|
||||||
void _convertBufferToWav(char* partialWavBuffer);
|
|
||||||
void _createWavHeader(byte* header, int waveDataSize);
|
void _createWavHeader(byte* header, int waveDataSize);
|
||||||
bool _isNoiseDetectedInPrecedingBuffer();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Audio(MicType micType, i2s_port_t i2sNum=I2S_NUM_0);
|
Audio(MicType micType);
|
||||||
~Audio();
|
~Audio();
|
||||||
char** record();
|
char** record();
|
||||||
int getSize();
|
int getSize();
|
||||||
String print(Stream* stream);
|
String print(Stream* stream);
|
||||||
String printHeader(Stream* stream);
|
|
||||||
String printContent(Stream* stream);
|
|
||||||
unsigned long getStartMicros();
|
unsigned long getStartMicros();
|
||||||
void emptyPrecedingBuffer();
|
bool isNoiseDetected(int threshold);
|
||||||
void writeToPrecedingBuffer();
|
|
||||||
bool isNoiseDetected();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _AUDIO_H
|
#endif // _AUDIO_H
|
||||||
|
@ -62,8 +62,6 @@ void Http::printContentLength(int contentLength) {
|
|||||||
_client->print("Content-Length: ");
|
_client->print("Content-Length: ");
|
||||||
_client->println(contentLength);
|
_client->println(contentLength);
|
||||||
_client->println();
|
_client->println();
|
||||||
|
|
||||||
_logContentLength(contentLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String Http::readResponse() {
|
String Http::readResponse() {
|
||||||
@ -135,8 +133,3 @@ void Http::_logPayload(String payload) {
|
|||||||
Serial.println(payload);
|
Serial.println(payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Http::_logContentLength(int contentLength) {
|
|
||||||
Serial.print("| Content-Length: ");
|
|
||||||
Serial.println(contentLength);
|
|
||||||
}
|
|
@ -11,7 +11,6 @@ private:
|
|||||||
void _logHeader(String method, String endpoint, String host, String contentType);
|
void _logHeader(String method, String endpoint, String host, String contentType);
|
||||||
void _logPayload(String payload);
|
void _logPayload(String payload);
|
||||||
void _logConnected(String host, int port);
|
void _logConnected(String host, int port);
|
||||||
void _logContentLength(int contentLength);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Http(Eth* eth);
|
Http(Eth* eth);
|
||||||
|
@ -1,24 +1,10 @@
|
|||||||
#include "infra/I2S.h"
|
#include "infra/I2S.h"
|
||||||
#include "config/config.h"
|
|
||||||
|
|
||||||
#define SAMPLE_RATE (16000)
|
#define SAMPLE_RATE (16000)
|
||||||
|
#define PIN_I2S_BCLK (GPIO_NUM_26)
|
||||||
// Define pins for I2S_NUM_0
|
#define PIN_I2S_LRC (GPIO_NUM_25)
|
||||||
#define PIN_I2S_0_BCLK (GPIO_NUM_26)
|
#define PIN_I2S_DIN (GPIO_NUM_3)
|
||||||
#define PIN_I2S_0_LRC (GPIO_NUM_25)
|
#define PIN_I2S_DOUT (GPIO_NUM_22)
|
||||||
#define PIN_I2S_0_DIN (GPIO_NUM_3)
|
#define PIN_I2S_MCK (GPIO_NUM_0)
|
||||||
#define PIN_I2S_0_DOUT (GPIO_NUM_22)
|
|
||||||
#define PIN_I2S_0_MCK (GPIO_NUM_0)
|
|
||||||
|
|
||||||
// Define pins for I2S_NUM_1
|
|
||||||
#define PIN_I2S_1_BCLK (GPIO_NUM_32)
|
|
||||||
#define PIN_I2S_1_LRC (GPIO_NUM_33)
|
|
||||||
#define PIN_I2S_1_DIN (GPIO_NUM_35)
|
|
||||||
#define PIN_I2S_1_DOUT (GPIO_NUM_0)
|
|
||||||
#define PIN_I2S_1_MCK (GPIO_NUM_0)
|
|
||||||
|
|
||||||
SemaphoreHandle_t dmaInterruptSemaphore;
|
|
||||||
static intr_handle_t dmaInterruptRetHandle;
|
|
||||||
|
|
||||||
// This I2S specification :
|
// This I2S specification :
|
||||||
// - LRC high is channel 2 (right).
|
// - LRC high is channel 2 (right).
|
||||||
@ -27,7 +13,7 @@ static intr_handle_t dmaInterruptRetHandle;
|
|||||||
// - Data bits are MSB first.
|
// - Data bits are MSB first.
|
||||||
// - DATA bits are left-aligned with respect to LRC edge.
|
// - DATA bits are left-aligned with respect to LRC edge.
|
||||||
// - DATA bits are right-shifted by one with respect to LRC edges.
|
// - DATA bits are right-shifted by one with respect to LRC edges.
|
||||||
I2S::I2S(MicType micType, i2s_port_t i2sNum) : _i2sNum(i2sNum) {
|
I2S::I2S(MicType micType) {
|
||||||
if (micType == M5GO || micType == M5STACKFIRE ) {
|
if (micType == M5GO || micType == M5STACKFIRE ) {
|
||||||
BITS_PER_SAMPLE = I2S_BITS_PER_SAMPLE_16BIT;
|
BITS_PER_SAMPLE = I2S_BITS_PER_SAMPLE_16BIT;
|
||||||
i2s_config_t i2s_config = {
|
i2s_config_t i2s_config = {
|
||||||
@ -36,14 +22,14 @@ I2S::I2S(MicType micType, i2s_port_t i2sNum) : _i2sNum(i2sNum) {
|
|||||||
.bits_per_sample = BITS_PER_SAMPLE,
|
.bits_per_sample = BITS_PER_SAMPLE,
|
||||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||||
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB),
|
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB),
|
||||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
.intr_alloc_flags = 0,
|
||||||
.dma_buf_count = 2,
|
.dma_buf_count = 2,
|
||||||
.dma_buf_len = 1024
|
.dma_buf_len = 1024
|
||||||
};
|
};
|
||||||
i2s_driver_install(_i2sNum, &i2s_config, 0, NULL);
|
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
|
||||||
i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_6);
|
i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_6);
|
||||||
i2s_set_clk(_i2sNum, SAMPLE_RATE, BITS_PER_SAMPLE, I2S_CHANNEL_STEREO);
|
i2s_set_clk(I2S_NUM_0, SAMPLE_RATE, BITS_PER_SAMPLE, I2S_CHANNEL_STEREO);
|
||||||
i2s_adc_enable(_i2sNum);
|
i2s_adc_enable(I2S_NUM_0);
|
||||||
}
|
}
|
||||||
else if (micType == ADMP441 || micType == ICS43434 ) {
|
else if (micType == ADMP441 || micType == ICS43434 ) {
|
||||||
BITS_PER_SAMPLE = I2S_BITS_PER_SAMPLE_16BIT;// I2S_BITS_PER_SAMPLE_32BIT;
|
BITS_PER_SAMPLE = I2S_BITS_PER_SAMPLE_16BIT;// I2S_BITS_PER_SAMPLE_32BIT;
|
||||||
@ -53,44 +39,29 @@ I2S::I2S(MicType micType, i2s_port_t i2sNum) : _i2sNum(i2sNum) {
|
|||||||
.bits_per_sample = BITS_PER_SAMPLE,
|
.bits_per_sample = BITS_PER_SAMPLE,
|
||||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||||
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
|
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
|
||||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
.intr_alloc_flags = 0,
|
||||||
.dma_buf_count = 16,
|
.dma_buf_count = 16,
|
||||||
.dma_buf_len = 60,
|
.dma_buf_len = 60
|
||||||
};
|
};
|
||||||
|
|
||||||
i2s_driver_install(_i2sNum, &i2s_config, 0, NULL);
|
|
||||||
_setPins();
|
|
||||||
i2s_set_clk(_i2sNum, SAMPLE_RATE, BITS_PER_SAMPLE, I2S_CHANNEL_STEREO);
|
|
||||||
i2s_zero_dma_buffer(_i2sNum);
|
|
||||||
}
|
|
||||||
|
|
||||||
dmaInterruptSemaphore = xSemaphoreCreateBinary();
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2S::_setPins() {
|
|
||||||
i2s_pin_config_t pin_config;
|
i2s_pin_config_t pin_config;
|
||||||
|
|
||||||
if (_i2sNum == I2S_NUM_0) {
|
pin_config.bck_io_num = PIN_I2S_BCLK;
|
||||||
pin_config.bck_io_num = PIN_I2S_0_BCLK;
|
pin_config.ws_io_num = PIN_I2S_LRC;
|
||||||
pin_config.ws_io_num = PIN_I2S_0_LRC;
|
|
||||||
pin_config.data_out_num = I2S_PIN_NO_CHANGE;
|
pin_config.data_out_num = I2S_PIN_NO_CHANGE;
|
||||||
pin_config.data_in_num = PIN_I2S_0_DIN;
|
pin_config.data_in_num = PIN_I2S_DIN;
|
||||||
pin_config.mck_io_num = PIN_I2S_0_MCK;
|
pin_config.mck_io_num = PIN_I2S_MCK;
|
||||||
} else if (_i2sNum == I2S_NUM_1) {
|
|
||||||
pin_config.bck_io_num = PIN_I2S_1_BCLK;
|
|
||||||
pin_config.ws_io_num = PIN_I2S_1_LRC;
|
|
||||||
pin_config.data_out_num = I2S_PIN_NO_CHANGE;
|
|
||||||
pin_config.data_in_num = PIN_I2S_1_DIN;
|
|
||||||
pin_config.mck_io_num = PIN_I2S_1_MCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
i2s_set_pin(_i2sNum, &pin_config);
|
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
|
||||||
|
i2s_set_pin(I2S_NUM_0, &pin_config);
|
||||||
|
i2s_set_clk(I2S_NUM_0, SAMPLE_RATE, BITS_PER_SAMPLE, I2S_CHANNEL_STEREO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int I2S::Read(char* data, int numData) {
|
int I2S::Read(char* data, int numData) {
|
||||||
size_t bytes_read;
|
size_t bytes_read;
|
||||||
|
|
||||||
if (i2s_read(_i2sNum, (char *)data, numData, &bytes_read, portMAX_DELAY)) {
|
if (i2s_read(I2S_NUM_0, (char *)data, numData, &bytes_read, portMAX_DELAY)) {
|
||||||
return (int)bytes_read;
|
return (int)bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,15 +14,11 @@ enum MicType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class I2S {
|
class I2S {
|
||||||
|
i2s_bits_per_sample_t BITS_PER_SAMPLE;
|
||||||
public:
|
public:
|
||||||
I2S(MicType micType, i2s_port_t i2sNum=I2S_NUM_0);
|
I2S(MicType micType);
|
||||||
int Read(char* data, int numData);
|
int Read(char* data, int numData);
|
||||||
int GetBitPerSample();
|
int GetBitPerSample();
|
||||||
|
|
||||||
private:
|
|
||||||
i2s_port_t _i2sNum;
|
|
||||||
i2s_bits_per_sample_t BITS_PER_SAMPLE;
|
|
||||||
void _setPins();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _I2S_H
|
#endif // _I2S_H
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
enum class CircularBufferErrorCode {
|
|
||||||
SUCCESS,
|
|
||||||
BUFFER_FULL,
|
|
||||||
BUFFER_EMPTY,
|
|
||||||
MEMORY_ERROR
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class CircularBuffer {
|
|
||||||
public:
|
|
||||||
CircularBuffer(size_t _capacity) : _capacity(_capacity) {
|
|
||||||
_buffer = static_cast<T*>(malloc(_capacity * sizeof(T)));
|
|
||||||
if (_buffer == nullptr) {
|
|
||||||
// Handle memory allocation error
|
|
||||||
_errorCode = CircularBufferErrorCode::MEMORY_ERROR;
|
|
||||||
} else {
|
|
||||||
_bufferEnd = _buffer + _capacity;
|
|
||||||
_count = 0;
|
|
||||||
_head = _buffer;
|
|
||||||
_tail = _buffer;
|
|
||||||
_errorCode = CircularBufferErrorCode::SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~CircularBuffer() {
|
|
||||||
free(_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
CircularBufferErrorCode pushBack(const T& item) {
|
|
||||||
if (isFull()) {
|
|
||||||
return CircularBufferErrorCode::BUFFER_FULL;
|
|
||||||
}
|
|
||||||
*_head = item;
|
|
||||||
_head++;
|
|
||||||
if (_head == _bufferEnd) {
|
|
||||||
_head = _buffer;
|
|
||||||
}
|
|
||||||
_count++;
|
|
||||||
return CircularBufferErrorCode::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
CircularBufferErrorCode popFront(T& item) {
|
|
||||||
if (isEmpty()) {
|
|
||||||
return CircularBufferErrorCode::BUFFER_EMPTY;
|
|
||||||
}
|
|
||||||
item = *_tail;
|
|
||||||
_tail++;
|
|
||||||
if (_tail == _bufferEnd) {
|
|
||||||
_tail = _buffer;
|
|
||||||
}
|
|
||||||
_count--;
|
|
||||||
return CircularBufferErrorCode::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isFull() {
|
|
||||||
return _count == _capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEmpty() {
|
|
||||||
return _count == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
T *_buffer; // Data _buffer
|
|
||||||
T *_bufferEnd; // End of data buffer
|
|
||||||
size_t _capacity; // Maximum number of items in the buffer
|
|
||||||
size_t _count; // Number of items in the buffer
|
|
||||||
T *_head; // Pointer to head
|
|
||||||
T *_tail; // Pointer to tail
|
|
||||||
CircularBufferErrorCode _errorCode; // Error code
|
|
||||||
};
|
|
39
src/main.cpp
39
src/main.cpp
@ -10,10 +10,7 @@
|
|||||||
#include "infra/Http.h"
|
#include "infra/Http.h"
|
||||||
#include "infra/Eth.h"
|
#include "infra/Eth.h"
|
||||||
|
|
||||||
#include "domain/Controller.h"
|
#include "domain/Recorder.h"
|
||||||
#include "domain/AidStrategy.h"
|
|
||||||
|
|
||||||
volatile bool loudnessFlag = false;
|
|
||||||
|
|
||||||
unsigned long beginMicros, endMicros;
|
unsigned long beginMicros, endMicros;
|
||||||
|
|
||||||
@ -21,7 +18,7 @@ Eth eth;
|
|||||||
EthernetClient* client = eth.getEthClient();
|
EthernetClient* client = eth.getEthClient();
|
||||||
Http http(ð);
|
Http http(ð);
|
||||||
|
|
||||||
Controller& controller = Controller::getInstance();
|
Recorder* recorder;
|
||||||
|
|
||||||
Time timeService = Time::getInstance();
|
Time timeService = Time::getInstance();
|
||||||
|
|
||||||
@ -38,24 +35,6 @@ void setInitialTime() {
|
|||||||
timeService.setInitialTime(currentTime);
|
timeService.setInitialTime(currentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeToPrecedingBufferTask(void* parameter) {
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void createWriteToPrecedingBufferTask() {
|
|
||||||
TaskHandle_t xHandle = NULL;
|
|
||||||
|
|
||||||
xTaskCreatePinnedToCore(writeToPrecedingBufferTask,
|
|
||||||
"writeToPrecedingBufferTask", 4096, NULL, 1, &xHandle, 0);
|
|
||||||
|
|
||||||
if (xHandle == NULL) {
|
|
||||||
ESP_LOGE("TASK1", "Failed to task create");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
delay(1000);
|
delay(1000);
|
||||||
@ -63,10 +42,7 @@ void setup() {
|
|||||||
eth.initEthernet();
|
eth.initEthernet();
|
||||||
|
|
||||||
setInitialTime();
|
setInitialTime();
|
||||||
Serial.println(1);
|
recorder = new Recorder(ADMP441, &http);
|
||||||
controller.setStrategy(new AidStrategy(ADMP441, &http));
|
|
||||||
|
|
||||||
//createWriteToPrecedingBufferTask();
|
|
||||||
|
|
||||||
beginMicros = micros();
|
beginMicros = micros();
|
||||||
}
|
}
|
||||||
@ -74,5 +50,12 @@ void setup() {
|
|||||||
void loop() {
|
void loop() {
|
||||||
eth.readAndPrintData(true); // set to false for better speed measurement
|
eth.readAndPrintData(true); // set to false for better speed measurement
|
||||||
|
|
||||||
controller.process();
|
if (recorder->isNoiseDetected(NOISE_THRESHOLD)) {
|
||||||
|
recorder->recordAudio();
|
||||||
|
}
|
||||||
|
|
||||||
|
//recorder->recordAudio();
|
||||||
|
//delay(15000);
|
||||||
|
|
||||||
|
//eth.handleDisconnect(beginMicros, micros());
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.8)
|
|
||||||
project(arduino-mock-test-all)
|
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
|
||||||
add_subdirectory(arduino_mock)
|
|
||||||
|
|
||||||
include_directories(
|
|
||||||
${ARDUINO_MOCK_INCLUDE_DIRS}
|
|
||||||
${ARDUINO_MOCK_LIBS_DIR}/lib/gtest/gtest/src/gtest/googletest/include
|
|
||||||
${ARDUINO_MOCK_LIBS_DIR}/lib/gtest/gtest/src/gtest/googlemock/include
|
|
||||||
)
|
|
||||||
message(ARDUINO_MOCK_INCLUDE_DIRS="${ARDUINO_MOCK_INCLUDE_DIRS}")
|
|
||||||
|
|
||||||
file(GLOB LIBS_SRCS "libs/*.cpp")
|
|
||||||
file(GLOB SRCS "*.cpp")
|
|
||||||
add_executable(test-all ${SRCS} ${LIBS_SRCS})
|
|
||||||
|
|
||||||
target_link_libraries(test-all
|
|
||||||
${ARDUINO_MOCK_LIBS_DIR}/lib/gtest/gtest/src/gtest-build/googlemock/gtest/libgtest.a
|
|
||||||
${ARDUINO_MOCK_LIBS_DIR}/lib/gtest/gtest/src/gtest-build/googlemock/libgmock.a
|
|
||||||
${ARDUINO_MOCK_LIBS_DIR}/dist/lib/libarduino_mock.a
|
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_dependencies(test-all arduino_mock)
|
|
||||||
|
|
||||||
enable_testing()
|
|
||||||
add_test(TestAll test-all)
|
|
@ -1,10 +0,0 @@
|
|||||||
/*
|
|
||||||
* TestAll.cpp
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
|
||||||
return RUN_ALL_TESTS();
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.8)
|
|
||||||
project(arduino_mock_builder C CXX)
|
|
||||||
include(ExternalProject)
|
|
||||||
|
|
||||||
ExternalProject_Add(arduino_mock
|
|
||||||
GIT_REPOSITORY https://github.com/wjszlachta/arduino-mock.git
|
|
||||||
GIT_TAG master
|
|
||||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/arduino_mock
|
|
||||||
INSTALL_COMMAND ""
|
|
||||||
)
|
|
||||||
|
|
||||||
ExternalProject_Get_Property(arduino_mock source_dir)
|
|
||||||
set(ARDUINO_MOCK_INCLUDE_DIRS ${source_dir}/include/arduino-mock PARENT_SCOPE)
|
|
||||||
|
|
||||||
ExternalProject_Get_Property(arduino_mock binary_dir)
|
|
||||||
set(ARDUINO_MOCK_LIBS_DIR ${binary_dir} PARENT_SCOPE)
|
|
@ -1,9 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
cd -- "$(dirname -- "$0")"
|
|
||||||
mkdir -p build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make
|
|
||||||
ctest -V
|
|
@ -1,117 +0,0 @@
|
|||||||
#include <gtest/gtest.h>
|
|
||||||
#include "../../src/libs/CircularBuffer.h"
|
|
||||||
|
|
||||||
// Test fixture for CircularBuffer
|
|
||||||
class CircularBufferTest : public ::testing::Test {
|
|
||||||
protected:
|
|
||||||
void SetUp() override {
|
|
||||||
// Initialization code that runs before each test
|
|
||||||
buffer = new CircularBuffer<int>(3); // Create a circular buffer of integers with capacity 5
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown() override {
|
|
||||||
// Clean-up code that runs after each test
|
|
||||||
delete buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Member variables accessible in test cases
|
|
||||||
CircularBuffer<int>* buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Test CircularBuffer push and pop operations
|
|
||||||
TEST_F(CircularBufferTest, PushAndPop) {
|
|
||||||
// Push some integers into the circular buffer
|
|
||||||
EXPECT_EQ(buffer->pushBack(10), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(buffer->pushBack(20), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(buffer->pushBack(30), CircularBufferErrorCode::SUCCESS);
|
|
||||||
|
|
||||||
// Pop integers from the circular buffer and check values
|
|
||||||
int item;
|
|
||||||
EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(item, 10);
|
|
||||||
EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(item, 20);
|
|
||||||
EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(item, 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test CircularBuffer with different types
|
|
||||||
TEST_F(CircularBufferTest, DifferentTypes) {
|
|
||||||
// Create a circular buffer of characters with capacity 3
|
|
||||||
CircularBuffer<char> charBuffer(3);
|
|
||||||
|
|
||||||
// Push some characters into the circular buffer
|
|
||||||
EXPECT_EQ(charBuffer.pushBack('a'), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(charBuffer.pushBack('b'), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(charBuffer.pushBack('c'), CircularBufferErrorCode::SUCCESS);
|
|
||||||
|
|
||||||
// Pop characters from the circular buffer and check values
|
|
||||||
char c;
|
|
||||||
EXPECT_EQ(charBuffer.popFront(c), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(c, 'a');
|
|
||||||
EXPECT_EQ(charBuffer.popFront(c), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(c, 'b');
|
|
||||||
EXPECT_EQ(charBuffer.popFront(c), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(c, 'c');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test CircularBuffer with full and empty conditions
|
|
||||||
TEST_F(CircularBufferTest, FullAndEmpty) {
|
|
||||||
// Fill up the buffer
|
|
||||||
buffer->pushBack(10);
|
|
||||||
buffer->pushBack(20);
|
|
||||||
buffer->pushBack(30);
|
|
||||||
|
|
||||||
// Try pushing into a full buffer
|
|
||||||
EXPECT_EQ(buffer->pushBack(40), CircularBufferErrorCode::BUFFER_FULL);
|
|
||||||
|
|
||||||
// Pop all elements from the buffer
|
|
||||||
int item;
|
|
||||||
EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::SUCCESS);
|
|
||||||
|
|
||||||
// Try popping from an empty buffer
|
|
||||||
EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::BUFFER_EMPTY);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test CircularBuffer with nested CircularBuffer
|
|
||||||
TEST_F(CircularBufferTest, CircularBufferWithNestedCircularBuffer) {
|
|
||||||
CircularBuffer<CircularBuffer<char>*> charBuffer(2);
|
|
||||||
|
|
||||||
CircularBuffer<char> charSubBuffer1(3);
|
|
||||||
CircularBuffer<char> charSubBuffer2(3);
|
|
||||||
|
|
||||||
EXPECT_EQ(charSubBuffer1.pushBack('a'), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(charSubBuffer1.pushBack('b'), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(charSubBuffer1.pushBack('c'), CircularBufferErrorCode::SUCCESS);
|
|
||||||
|
|
||||||
EXPECT_EQ(charSubBuffer2.pushBack('d'), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(charSubBuffer2.pushBack('e'), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(charSubBuffer2.pushBack('f'), CircularBufferErrorCode::SUCCESS);
|
|
||||||
|
|
||||||
EXPECT_EQ(charBuffer.pushBack(&charSubBuffer1), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(charBuffer.pushBack(&charSubBuffer2), CircularBufferErrorCode::SUCCESS);
|
|
||||||
|
|
||||||
CircularBuffer<char>* poppedCharSubBuffer;
|
|
||||||
EXPECT_EQ(charBuffer.popFront(poppedCharSubBuffer), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(poppedCharSubBuffer, &charSubBuffer1);
|
|
||||||
|
|
||||||
char c;
|
|
||||||
EXPECT_EQ(poppedCharSubBuffer->popFront(c), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(c, 'a');
|
|
||||||
EXPECT_EQ(poppedCharSubBuffer->popFront(c), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(c, 'b');
|
|
||||||
EXPECT_EQ(poppedCharSubBuffer->popFront(c), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(c, 'c');
|
|
||||||
|
|
||||||
EXPECT_EQ(charBuffer.popFront(poppedCharSubBuffer), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(poppedCharSubBuffer, &charSubBuffer2);
|
|
||||||
|
|
||||||
EXPECT_EQ(poppedCharSubBuffer->popFront(c), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(c, 'd');
|
|
||||||
EXPECT_EQ(poppedCharSubBuffer->popFront(c), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(c, 'e');
|
|
||||||
EXPECT_EQ(poppedCharSubBuffer->popFront(c), CircularBufferErrorCode::SUCCESS);
|
|
||||||
EXPECT_EQ(c, 'f');
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user