Last active
October 2, 2023 23:44
-
-
Save 2200913/21e7624603863b5a339a98b6594404cb to your computer and use it in GitHub Desktop.
Sistemas Computacionais Embebidos, projeto melhoria
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* FTP Serveur for ESP8266 | |
* based on FTP Serveur for Arduino Due and Ethernet shield (W5100) or WIZ820io (W5200) | |
* based on Jean-Michel Gallego's work | |
* modified to work with esp8266 SPIFFS by David Paiva david@nailbuster.com | |
* | |
* This program is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation, either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
// 2017: modified by @robo8080 | |
// 2019: modified by @HenrikSte | |
#include "ESP32FtpServer.h" | |
#include <WiFi.h> | |
#include <WiFiClient.h> | |
//#include <ESP32WebServer.h> | |
#include <FS.h> | |
//#include "SD.h" | |
#include "SD.h" | |
#include "SPI.h" | |
#define FTP_DEBUG | |
WiFiServer ftpServer( FTP_CTRL_PORT ); | |
WiFiServer dataServer( FTP_DATA_PORT_PASV ); | |
FtpServer::FtpServer() | |
{ | |
} | |
void FtpServer::begin(String uname, String pword) | |
{ | |
// Tells the ftp server to begin listening for incoming connection | |
_FTP_USER=uname; | |
_FTP_PASS = pword; | |
if(!SD.begin()) | |
{ | |
Serial.println("Card Mount Failed"); | |
return; | |
} | |
uint8_t cardType = SD.cardType(); | |
if(cardType == CARD_NONE){ | |
Serial.println("No SD card attached"); | |
return; | |
} | |
Serial.print("SD Card Type: "); | |
if(cardType == CARD_MMC){ | |
Serial.println("MMC"); | |
} else if(cardType == CARD_SD){ | |
Serial.println("SDSC"); | |
} else if(cardType == CARD_SDHC){ | |
Serial.println("SDHC"); | |
} else { | |
Serial.println("UNKNOWN"); | |
} | |
ftpServer.begin(); | |
delay(10); | |
dataServer.begin(); | |
delay(10); | |
millisTimeOut = (uint32_t)FTP_TIME_OUT * 60 * 1000; | |
millisDelay = 0; | |
cmdStatus = 0; | |
iniVariables(); | |
} | |
void FtpServer::iniVariables() | |
{ | |
// Default for data port | |
dataPort = FTP_DATA_PORT_PASV; | |
// Default Data connection is Active | |
dataPassiveConn = true; | |
// Set the root directory | |
strcpy( cwdName, "/" ); | |
rnfrCmd = false; | |
transferStatus = 0; | |
} | |
int FtpServer::handleFTP() | |
{ | |
if((int32_t) ( millisDelay - millis() ) > 0 ) | |
return 0; | |
if (ftpServer.hasClient()) { | |
// if (ftpServer.available()) { | |
client.stop(); | |
client = ftpServer.available(); | |
} | |
if( cmdStatus == 0 ) | |
{ | |
if( client.connected()) | |
disconnectClient(); | |
cmdStatus = 1; | |
} | |
else if( cmdStatus == 1 ) // Ftp server waiting for connection | |
{ | |
abortTransfer(); | |
iniVariables(); | |
#ifdef FTP_DEBUG | |
Serial.println("Ftp server waiting for connection on port "+ String(FTP_CTRL_PORT)); | |
#endif | |
cmdStatus = 2; | |
} | |
else if( cmdStatus == 2 ) // Ftp server idle | |
{ | |
if( client.connected() ) // A client connected | |
{ | |
clientConnected(); | |
millisEndConnection = millis() + 10 * 1000 ; // wait client id during 10 s. | |
cmdStatus = 3; | |
} | |
} | |
else if( readChar() > 0 ) // got response | |
{ | |
if( cmdStatus == 3 ) // Ftp server waiting for user identity | |
if( userIdentity() ) | |
cmdStatus = 4; | |
else | |
cmdStatus = 0; | |
else if( cmdStatus == 4 ) // Ftp server waiting for user registration | |
if( userPassword() ) | |
{ | |
cmdStatus = 5; | |
millisEndConnection = millis() + millisTimeOut; | |
} | |
else | |
cmdStatus = 0; | |
else if( cmdStatus == 5 ) // Ftp server waiting for user command | |
{ | |
if( ! processCommand()) | |
cmdStatus = 0; | |
else | |
millisEndConnection = millis() + millisTimeOut; | |
} | |
} | |
else if (!client.connected() || !client) | |
{ | |
cmdStatus = 1; | |
#ifdef FTP_DEBUG | |
Serial.println("client disconnected"); | |
#endif | |
} | |
if( transferStatus == 1 ) // Retrieve data | |
{ | |
if( ! doRetrieve()) | |
transferStatus = 0; | |
} | |
else if( transferStatus == 2 ) // Store data | |
{ | |
if( ! doStore()) | |
transferStatus = 0; | |
} | |
else if( cmdStatus > 2 && ! ((int32_t) ( millisEndConnection - millis() ) > 0 )) | |
{ | |
client.println("530 Timeout"); | |
millisDelay = millis() + 200; // delay of 200 ms | |
cmdStatus = 0; | |
} | |
return transferStatus!=0 | |
|| cmdStatus !=0; | |
} | |
void FtpServer::clientConnected() | |
{ | |
#ifdef FTP_DEBUG | |
Serial.println("Client connected!"); | |
#endif | |
client.println( "220--- Welcome to FTP for ESP32 ---"); | |
client.println( "220--- By David Paiva ---"); | |
client.println( "220 -- Version "+ String(FTP_SERVER_VERSION) +" --"); | |
iCL = 0; | |
} | |
void FtpServer::disconnectClient() | |
{ | |
#ifdef FTP_DEBUG | |
Serial.println(" Disconnecting client"); | |
#endif | |
abortTransfer(); | |
client.println("221 Goodbye"); | |
client.stop(); | |
} | |
boolean FtpServer::userIdentity() | |
{ | |
if( strcmp( command, "USER" )) | |
client.println( "500 Syntax error"); | |
if( strcmp( parameters, _FTP_USER.c_str() )) | |
client.println( "530 user not found"); | |
else | |
{ | |
client.println( "331 OK. Password required"); | |
strcpy( cwdName, "/" ); | |
return true; | |
} | |
millisDelay = millis() + 100; // delay of 100 ms | |
return false; | |
} | |
boolean FtpServer::userPassword() | |
{ | |
if( strcmp( command, "PASS" )) | |
client.println( "500 Syntax error"); | |
else if( strcmp( parameters, _FTP_PASS.c_str() )) | |
client.println( "530 "); | |
else | |
{ | |
#ifdef FTP_DEBUG | |
Serial.println( "OK. Waiting for commands."); | |
#endif | |
client.println( "230 OK."); | |
return true; | |
} | |
millisDelay = millis() + 100; // delay of 100 ms | |
return false; | |
} | |
boolean FtpServer::processCommand() | |
{ | |
/////////////////////////////////////// | |
// // | |
// ACCESS CONTROL COMMANDS // | |
// // | |
/////////////////////////////////////// | |
// | |
// CDUP - Change to Parent Directory | |
// | |
if( ! strcmp( command, "CDUP" )) | |
{ | |
int todo; | |
client.println("250 Ok. Current directory is \"" + String(cwdName) + "\""); | |
} | |
// | |
// CWD - Change Working Directory | |
// | |
else if( ! strcmp( command, "CWD" )) | |
{ | |
if( strcmp( parameters, "." ) == 0 ) // 'CWD .' is the same as PWD command | |
client.println( "257 \"" + String(cwdName) + "\" is your current directory"); | |
else | |
{ | |
#ifdef FTP_DEBUG | |
Serial.print("CWD P="); | |
Serial.print(parameters); | |
Serial.print(" CWD="); | |
Serial.println(cwdName); | |
#endif | |
String dir; | |
if (parameters[0]=='/') | |
{ | |
dir = parameters; | |
} | |
else if (!strcmp(cwdName,"/")) // avoid "\\newdir" | |
{ | |
dir = String("/") + parameters; | |
} | |
else | |
{ | |
dir = String(cwdName) +"/" + parameters; | |
} | |
if (SD.exists(dir)) | |
{ | |
strcpy(cwdName, dir.c_str()); | |
client.println( "250 CWD Ok. Current directory is \"" + String(dir) + "\""); | |
Serial.println( "250 CWD Ok. Current directory is \"" + String(dir) + "\""); | |
} | |
else | |
{ | |
client.println( "550 directory or file does not exist \"" + String(parameters) + "\""); | |
Serial.println( "550 directory or file does not exist \"" + String(parameters) + "\""); | |
} | |
} | |
} | |
// | |
// PWD - Print Directory | |
// | |
else if( ! strcmp( command, "PWD" )) | |
client.println( "257 \"" + String(cwdName) + "\" is your current directory"); | |
// | |
// QUIT | |
// | |
else if( ! strcmp( command, "QUIT" )) | |
{ | |
disconnectClient(); | |
return false; | |
} | |
/////////////////////////////////////// | |
// // | |
// TRANSFER PARAMETER COMMANDS // | |
// // | |
/////////////////////////////////////// | |
// | |
// MODE - Transfer Mode | |
// | |
else if( ! strcmp( command, "MODE" )) | |
{ | |
if( ! strcmp( parameters, "S" )) | |
client.println( "200 S Ok"); | |
// else if( ! strcmp( parameters, "B" )) | |
// client.println( "200 B Ok\r\n"; | |
else | |
client.println( "504 Only S(tream) is suported"); | |
} | |
// | |
// PASV - Passive Connection management | |
// | |
else if( ! strcmp( command, "PASV" )) | |
{ | |
if (data.connected()) data.stop(); | |
//dataServer.begin(); | |
//dataIp = Ethernet.localIP(); | |
dataIp = WiFi.localIP(); | |
dataPort = FTP_DATA_PORT_PASV; | |
//data.connect( dataIp, dataPort ); | |
//data = dataServer.available(); | |
#ifdef FTP_DEBUG | |
Serial.println("Connection management set to passive"); | |
Serial.println( "Data port set to " + String(dataPort)); | |
#endif | |
client.println( "227 Entering Passive Mode ("+ String(dataIp[0]) + "," + String(dataIp[1])+","+ String(dataIp[2])+","+ String(dataIp[3])+","+String( dataPort >> 8 ) +","+String ( dataPort & 255 )+")."); | |
dataPassiveConn = true; | |
} | |
// | |
// PORT - Data Port | |
// | |
else if( ! strcmp( command, "PORT" )) | |
{ | |
if (data) data.stop(); | |
// get IP of data client | |
dataIp[ 0 ] = atoi( parameters ); | |
char * p = strchr( parameters, ',' ); | |
for( uint8_t i = 1; i < 4; i ++ ) | |
{ | |
dataIp[ i ] = atoi( ++ p ); | |
p = strchr( p, ',' ); | |
} | |
// get port of data client | |
dataPort = 256 * atoi( ++ p ); | |
p = strchr( p, ',' ); | |
dataPort += atoi( ++ p ); | |
if( p == NULL ) | |
client.println( "501 Can't interpret parameters"); | |
else | |
{ | |
client.println("200 PORT command successful"); | |
dataPassiveConn = false; | |
} | |
} | |
// | |
// STRU - File Structure | |
// | |
else if( ! strcmp( command, "STRU" )) | |
{ | |
if( ! strcmp( parameters, "F" )) | |
client.println( "200 F Ok"); | |
// else if( ! strcmp( parameters, "R" )) | |
// client.println( "200 B Ok\r\n"; | |
else | |
client.println( "504 Only F(ile) is suported"); | |
} | |
// | |
// TYPE - Data Type | |
// | |
else if( ! strcmp( command, "TYPE" )) | |
{ | |
if( ! strcmp( parameters, "A" )) | |
client.println( "200 TYPE is now ASII"); | |
else if( ! strcmp( parameters, "I" )) | |
client.println( "200 TYPE is now 8-bit binary"); | |
else | |
client.println( "504 Unknow TYPE"); | |
} | |
/////////////////////////////////////// | |
// // | |
// FTP SERVICE COMMANDS // | |
// // | |
/////////////////////////////////////// | |
// | |
// ABOR - Abort | |
// | |
else if( ! strcmp( command, "ABOR" )) | |
{ | |
abortTransfer(); | |
client.println( "226 Data connection closed"); | |
} | |
// | |
// DELE - Delete a File | |
// | |
else if( ! strcmp( command, "DELE" )) | |
{ | |
char path[ FTP_CWD_SIZE ]; | |
if( strlen( parameters ) == 0 ) | |
client.println( "501 No file name"); | |
else if( makePath( path )) | |
{ | |
if( ! SD.exists( path )) | |
client.println( "550 File " + String(parameters) + " not found"); | |
else | |
{ | |
if( SD.remove( path )) | |
client.println( "250 Deleted " + String(parameters) ); | |
else | |
client.println( "450 Can't delete " + String(parameters)); | |
} | |
} | |
} | |
// | |
// LIST - List | |
// | |
else if( ! strcmp( command, "LIST" )) | |
{ | |
if( ! dataConnect()) | |
client.println( "425 No data connection"); | |
else | |
{ | |
client.println( "150 Accepted data connection"); | |
uint16_t nm = 0; | |
// Dir dir=SD.openDir(cwdName); | |
File dir=SD.open(cwdName); | |
// if( !SD.exists(cwdName)) | |
if((!dir)||(!dir.isDirectory())) | |
client.println( "550 Can't open directory " + String(cwdName) ); | |
else | |
{ | |
File file = dir.openNextFile(); | |
while( file) | |
{ | |
String fn, fs; | |
fn = file.name(); | |
fn.remove(0, 1); | |
#ifdef FTP_DEBUG | |
Serial.println("File Name = "+ fn); | |
#endif | |
fs = String(file.size()); | |
if(file.isDirectory()){ | |
data.println( "01-01-2000 00:00AM <DIR> " + fn); | |
} else { | |
data.println( "01-01-2000 00:00AM " + fs + " " + fn); | |
// data.println( " " + fn ); | |
} | |
nm ++; | |
file = dir.openNextFile(); | |
} | |
client.println( "226 " + String(nm) + " matches total"); | |
} | |
data.stop(); | |
} | |
} | |
// | |
// MLSD - Listing for Machine Processing (see RFC 3659) | |
// | |
else if( ! strcmp( command, "MLSD" )) | |
{ | |
if( ! dataConnect()) | |
{ | |
client.println( "425 No data connection MLSD"); | |
} | |
else | |
{ | |
client.println( "150 Accepted data connection"); | |
uint16_t nm = 0; | |
// Dir dir= SD.openDir(cwdName); | |
File dir= SD.open(cwdName); | |
//char dtStr[ 15 ]; | |
// if(!SD.exists(cwdName)) | |
if((!dir)||(!dir.isDirectory())) | |
client.println( "550 Can't open directory " +String(cwdName) ); | |
// client.println( "550 Can't open directory " +String(parameters) ); | |
else | |
{ | |
// while( dir.next()) | |
File file = dir.openNextFile(); | |
// while( dir.openNextFile()) | |
while( file) | |
{ | |
String fn,fs; | |
fn = file.name(); | |
// Serial.println(fn); | |
fn.remove(0, strlen(cwdName)); | |
if(fn[0] == '/') fn.remove(0, 1); | |
fs = String(file.size()); | |
if(file.isDirectory()){ | |
data.println( "Type=dir;Size=" + fs + ";"+"modify=20000101000000;" +" " + fn); | |
// data.println( "Type=dir;modify=20000101000000; " + fn); | |
} else { | |
//data.println( "Type=file;Size=" + fs + ";"+"modify=20000101160656;" +" " + fn); | |
data.println( "Type=file;Size=" + fs + ";"+"modify=20000101000000;" +" " + fn); | |
} | |
nm ++; | |
file = dir.openNextFile(); | |
} | |
client.println( "226-options: -a -l"); | |
client.println( "226 " + String(nm) + " matches total"); | |
} | |
data.stop(); | |
} | |
} | |
// | |
// NLST - Name List | |
// | |
else if( ! strcmp( command, "NLST" )) | |
{ | |
if( ! dataConnect()) | |
client.println( "425 No data connection"); | |
else | |
{ | |
client.println( "150 Accepted data connection"); | |
uint16_t nm = 0; | |
// Dir dir=SD.openDir(cwdName); | |
File dir= SD.open(cwdName); | |
if( !SD.exists( cwdName )) | |
client.println( "550 Can't open directory " + String(parameters)); | |
else | |
{ | |
File file = dir.openNextFile(); | |
// while( dir.next()) | |
while( file) | |
{ | |
// data.println( dir.fileName()); | |
data.println( file.name()); | |
nm ++; | |
file = dir.openNextFile(); | |
} | |
client.println( "226 " + String(nm) + " matches total"); | |
} | |
data.stop(); | |
} | |
} | |
// | |
// NOOP | |
// | |
else if( ! strcmp( command, "NOOP" )) | |
{ | |
// dataPort = 0; | |
client.println( "200 Zzz..."); | |
} | |
// | |
// RETR - Retrieve | |
// | |
else if( ! strcmp( command, "RETR" )) | |
{ | |
char path[ FTP_CWD_SIZE ]; | |
if( strlen( parameters ) == 0 ) | |
client.println( "501 No file name"); | |
else if( makePath( path )) | |
{ | |
file = SD.open(path, "r"); | |
if( !file) | |
client.println( "550 File " +String(parameters)+ " not found"); | |
else if( !file ) | |
client.println( "450 Can't open " +String(parameters)); | |
else if( ! dataConnect()) | |
client.println( "425 No data connection"); | |
else | |
{ | |
#ifdef FTP_DEBUG | |
Serial.println("Sending " + String(parameters)); | |
#endif | |
client.println( "150-Connected to port "+ String(dataPort)); | |
client.println( "150 " + String(file.size()) + " bytes to download"); | |
millisBeginTrans = millis(); | |
bytesTransfered = 0; | |
transferStatus = 1; | |
} | |
} | |
} | |
// | |
// STOR - Store | |
// | |
else if( ! strcmp( command, "STOR" )) | |
{ | |
char path[ FTP_CWD_SIZE ]; | |
if( strlen( parameters ) == 0 ) | |
client.println( "501 No file name"); | |
else if( makePath( path )) | |
{ | |
file = SD.open(path, "w"); | |
if( !file) | |
client.println( "451 Can't open/create " +String(parameters) ); | |
else if( ! dataConnect()) | |
{ | |
client.println( "425 No data connection"); | |
file.close(); | |
} | |
else | |
{ | |
#ifdef FTP_DEBUG | |
Serial.println( "Receiving " +String(parameters)); | |
#endif | |
client.println( "150 Connected to port " + String(dataPort)); | |
millisBeginTrans = millis(); | |
bytesTransfered = 0; | |
transferStatus = 2; | |
} | |
} | |
} | |
// | |
// MKD - Make Directory | |
// | |
else if( ! strcmp( command, "MKD" )) | |
{ | |
#ifdef FTP_DEBUG | |
Serial.print("MKD P="); | |
Serial.print(parameters); | |
Serial.print(" CWD="); | |
Serial.println(cwdName); | |
#endif | |
String dir; | |
if (!strcmp(cwdName,"/")) // avoid "\\newdir" | |
{ | |
dir = String("/") + parameters; | |
} | |
else | |
{ | |
dir = String(cwdName) +"/" + parameters; | |
} | |
#ifdef FTP_DEBUG | |
Serial.print("try to create "); | |
Serial.println(dir); | |
#endif | |
fs::FS &fs = SD; | |
if (fs.mkdir(dir.c_str())) | |
{ | |
client.println( "257 \"" + String(parameters) + "\" - Directory successfully created"); | |
} | |
else | |
{ | |
client.println( "502 Can't create \"" + String(parameters)); | |
} | |
} | |
// | |
// RMD - Remove a Directory | |
// | |
else if( ! strcmp( command, "RMD" )) | |
{ | |
#ifdef FTP_DEBUG | |
Serial.print("RMD "); | |
Serial.print(parameters); | |
Serial.print(" CWD="); | |
Serial.println(cwdName); | |
#endif | |
String dir; | |
if (!strcmp(cwdName,"/")) // avoid "\\newdir" | |
{ | |
dir = String("/") + parameters; | |
} | |
else | |
{ | |
dir = String(cwdName) +"/" + parameters; | |
} | |
fs::FS &fs = SD; | |
if (fs.rmdir(dir.c_str())) | |
{ | |
client.println( "250 RMD command successful"); | |
} | |
else | |
{ | |
client.println( "502 Can't delete \"" + String(parameters)); //not support on espyet | |
} | |
} | |
// | |
// RNFR - Rename From | |
// | |
else if( ! strcmp( command, "RNFR" )) | |
{ | |
buf[ 0 ] = 0; | |
if( strlen( parameters ) == 0 ) | |
client.println( "501 No file name"); | |
else if( makePath( buf )) | |
{ | |
if( ! SD.exists( buf )) | |
client.println( "550 File " +String(parameters)+ " not found"); | |
else | |
{ | |
#ifdef FTP_DEBUG | |
Serial.println("Renaming " + String(buf)); | |
#endif | |
client.println( "350 RNFR accepted - file exists, ready for destination"); | |
rnfrCmd = true; | |
} | |
} | |
} | |
// | |
// RNTO - Rename To | |
// | |
else if( ! strcmp( command, "RNTO" )) | |
{ | |
char path[ FTP_CWD_SIZE ]; | |
//char dir[ FTP_FIL_SIZE ]; | |
if( strlen( buf ) == 0 || ! rnfrCmd ) | |
client.println( "503 Need RNFR before RNTO"); | |
else if( strlen( parameters ) == 0 ) | |
client.println( "501 No file name"); | |
else if( makePath( path )) | |
{ | |
if( SD.exists( path )) | |
client.println( "553 " +String(parameters)+ " already exists"); | |
else | |
{ | |
#ifdef FTP_DEBUG | |
Serial.println("Renaming " + String(buf) + " to " + String(path)); | |
#endif | |
if( SD.rename( buf, path )) | |
client.println( "250 File successfully renamed or moved"); | |
else | |
client.println( "451 Rename/move failure"); | |
} | |
} | |
rnfrCmd = false; | |
} | |
/////////////////////////////////////// | |
// // | |
// EXTENSIONS COMMANDS (RFC 3659) // | |
// // | |
/////////////////////////////////////// | |
// | |
// FEAT - New Features | |
// | |
else if( ! strcmp( command, "FEAT" )) | |
{ | |
client.println( "211-Extensions suported:"); | |
client.println( " MLSD"); | |
client.println( "211 End."); | |
} | |
// | |
// MDTM - File Modification Time (see RFC 3659) | |
// | |
else if (!strcmp(command, "MDTM")) | |
{ | |
client.println("550 Unable to retrieve time"); | |
} | |
// | |
// SIZE - Size of the file | |
// | |
else if( ! strcmp( command, "SIZE" )) | |
{ | |
char path[ FTP_CWD_SIZE ]; | |
if( strlen( parameters ) == 0 ) | |
client.println( "501 No file name"); | |
else if( makePath( path )) | |
{ | |
file = SD.open(path, "r"); | |
if(!file) | |
client.println( "450 Can't open " +String(parameters) ); | |
else | |
{ | |
client.println( "213 " + String(file.size())); | |
file.close(); | |
} | |
} | |
} | |
// | |
// SITE - System command | |
// | |
else if( ! strcmp( command, "SITE" )) | |
{ | |
client.println( "500 Unknow SITE command " +String(parameters) ); | |
} | |
// | |
// Unrecognized commands ... | |
// | |
else | |
client.println( "500 Unknow command"); | |
return true; | |
} | |
boolean FtpServer::dataConnect() | |
{ | |
unsigned long startTime = millis(); | |
//wait 5 seconds for a data connection | |
if (!data.connected()) | |
{ | |
while (!dataServer.hasClient() && millis() - startTime < 10000) | |
// while (!dataServer.available() && millis() - startTime < 10000) | |
{ | |
//delay(100); | |
yield(); | |
} | |
if (dataServer.hasClient()) { | |
// if (dataServer.available()) { | |
data.stop(); | |
data = dataServer.available(); | |
#ifdef FTP_DEBUG | |
Serial.println("ftpdataserver client...."); | |
#endif | |
} | |
} | |
return data.connected(); | |
} | |
boolean FtpServer::doRetrieve() | |
{ | |
//int16_t nb = file.readBytes((uint8_t*) buf, FTP_BUF_SIZE ); | |
int16_t nb = file.readBytes(buf, FTP_BUF_SIZE); | |
if( nb > 0 ) | |
{ | |
data.write((uint8_t*) buf, nb ); | |
bytesTransfered += nb; | |
return true; | |
} | |
closeTransfer(); | |
return false; | |
} | |
unsigned long count=0; | |
boolean FtpServer::doStore() | |
{ | |
if( data.connected() ) | |
{ | |
unsigned long ms0 = millis(); | |
//Serial.print("Transfer="); | |
int16_t nb = data.readBytes((uint8_t*) buf, FTP_BUF_SIZE ); | |
//unsigned long ms1 = millis(); | |
//Serial.print(ms1-ms0); | |
if( nb > 0 ) | |
{ | |
// Serial.println( millis() << " " << nb << endl; | |
//Serial.print("SD="); | |
size_t written = file.write((uint8_t*) buf, nb ); | |
/* | |
unsigned long ms2 = millis(); | |
Serial.print(ms2-ms1); | |
Serial.print("nb="); | |
Serial.print(nb); | |
Serial.print("w="); | |
Serial.println(written); | |
*/ | |
bytesTransfered += nb; | |
} | |
else | |
{ | |
Serial.println("."); | |
} | |
return true; | |
} | |
closeTransfer(); | |
return false; | |
} | |
void FtpServer::closeTransfer() | |
{ | |
uint32_t deltaT = (int32_t) ( millis() - millisBeginTrans ); | |
if( deltaT > 0 && bytesTransfered > 0 ) | |
{ | |
client.println( "226-File successfully transferred"); | |
client.println( "226 " + String(deltaT) + " ms, "+ String(bytesTransfered / deltaT) + " kbytes/s"); | |
} | |
else | |
client.println( "226 File successfully transferred"); | |
file.close(); | |
data.stop(); | |
} | |
void FtpServer::abortTransfer() | |
{ | |
if( transferStatus > 0 ) | |
{ | |
file.close(); | |
data.stop(); | |
client.println( "426 Transfer aborted" ); | |
#ifdef FTP_DEBUG | |
Serial.println( "Transfer aborted!") ; | |
#endif | |
} | |
transferStatus = 0; | |
} | |
// Read a char from client connected to ftp server | |
// | |
// update cmdLine and command buffers, iCL and parameters pointers | |
// | |
// return: | |
// -2 if buffer cmdLine is full | |
// -1 if line not completed | |
// 0 if empty line received | |
// length of cmdLine (positive) if no empty line received | |
int8_t FtpServer::readChar() | |
{ | |
int8_t rc = -1; | |
if( client.available()) | |
{ | |
char c = client.read(); | |
// char c; | |
// client.readBytes((uint8_t*) c, 1); | |
#ifdef FTP_DEBUG | |
Serial.print( c); | |
#endif | |
if( c == '\\' ) | |
{ | |
c = '/'; | |
} | |
if( c != '\r' ) | |
{ | |
if( c != '\n' ) | |
{ | |
if( iCL < FTP_CMD_SIZE ) | |
cmdLine[ iCL ++ ] = c; | |
else | |
rc = -2; // Line too long | |
} | |
else | |
{ | |
cmdLine[ iCL ] = 0; | |
command[ 0 ] = 0; | |
parameters = NULL; | |
// empty line? | |
if( iCL == 0 ) | |
rc = 0; | |
else | |
{ | |
rc = iCL; | |
// search for space between command and parameters | |
parameters = strchr( cmdLine, ' ' ); | |
if( parameters != NULL ) | |
{ | |
if( parameters - cmdLine > 4 ) | |
{ | |
rc = -2; // Syntax error | |
} | |
else | |
{ | |
strncpy( command, cmdLine, parameters - cmdLine ); | |
command[ parameters - cmdLine ] = 0; | |
while( * ( ++ parameters ) == ' ' ) | |
; | |
} | |
} | |
else if( strlen( cmdLine ) > 4 ) | |
rc = -2; // Syntax error. | |
else | |
strcpy( command, cmdLine ); | |
iCL = 0; | |
} | |
} | |
} | |
if( rc > 0 ) | |
{ | |
for( uint8_t i = 0 ; i < strlen( command ); i ++ ) | |
{ | |
command[ i ] = toupper( command[ i ] ); | |
} | |
} | |
if( rc == -2 ) | |
{ | |
iCL = 0; | |
client.println( "500 Syntax error"); | |
} | |
} | |
return rc; | |
} | |
// Make complete path/name from cwdName and parameters | |
// | |
// 3 possible cases: parameters can be absolute path, relative path or only the name | |
// | |
// parameters: | |
// fullName : where to store the path/name | |
// | |
// return: | |
// true, if done | |
boolean FtpServer::makePath( char * fullName ) | |
{ | |
return makePath( fullName, parameters ); | |
} | |
boolean FtpServer::makePath( char * fullName, char * param ) | |
{ | |
if( param == NULL ) | |
param = parameters; | |
// Root or empty? | |
if( strcmp( param, "/" ) == 0 || strlen( param ) == 0 ) | |
{ | |
strcpy( fullName, "/" ); | |
return true; | |
} | |
// If relative path, concatenate with current dir | |
if( param[0] != '/' ) | |
{ | |
strcpy( fullName, cwdName ); | |
if( fullName[ strlen( fullName ) - 1 ] != '/' ) | |
strncat( fullName, "/", FTP_CWD_SIZE ); | |
strncat( fullName, param, FTP_CWD_SIZE ); | |
} | |
else | |
strcpy( fullName, param ); | |
// If ends with '/', remove it | |
uint16_t strl = strlen( fullName ) - 1; | |
if( fullName[ strl ] == '/' && strl > 1 ) | |
fullName[ strl ] = 0; | |
if( strlen( fullName ) < FTP_CWD_SIZE ) | |
return true; | |
client.println( "500 Command line too long"); | |
return false; | |
} | |
// Calculate year, month, day, hour, minute and second | |
// from first parameter sent by MDTM command (YYYYMMDDHHMMSS) | |
// | |
// parameters: | |
// pyear, pmonth, pday, phour, pminute and psecond: pointer of | |
// variables where to store data | |
// | |
// return: | |
// 0 if parameter is not YYYYMMDDHHMMSS | |
// length of parameter + space | |
uint8_t FtpServer::getDateTime( uint16_t * pyear, uint8_t * pmonth, uint8_t * pday, | |
uint8_t * phour, uint8_t * pminute, uint8_t * psecond ) | |
{ | |
char dt[ 15 ]; | |
// Date/time are expressed as a 14 digits long string | |
// terminated by a space and followed by name of file | |
if( strlen( parameters ) < 15 || parameters[ 14 ] != ' ' ) | |
return 0; | |
for( uint8_t i = 0; i < 14; i++ ) | |
if( ! isdigit( parameters[ i ])) | |
return 0; | |
strncpy( dt, parameters, 14 ); | |
dt[ 14 ] = 0; | |
* psecond = atoi( dt + 12 ); | |
dt[ 12 ] = 0; | |
* pminute = atoi( dt + 10 ); | |
dt[ 10 ] = 0; | |
* phour = atoi( dt + 8 ); | |
dt[ 8 ] = 0; | |
* pday = atoi( dt + 6 ); | |
dt[ 6 ] = 0 ; | |
* pmonth = atoi( dt + 4 ); | |
dt[ 4 ] = 0 ; | |
* pyear = atoi( dt ); | |
return 15; | |
} | |
// Create string YYYYMMDDHHMMSS from date and time | |
// | |
// parameters: | |
// date, time | |
// tstr: where to store the string. Must be at least 15 characters long | |
// | |
// return: | |
// pointer to tstr | |
char * FtpServer::makeDateTimeStr( char * tstr, uint16_t date, uint16_t time ) | |
{ | |
sprintf( tstr, "%04u%02u%02u%02u%02u%02u", | |
(( date & 0xFE00 ) >> 9 ) + 1980, ( date & 0x01E0 ) >> 5, date & 0x001F, | |
( time & 0xF800 ) >> 11, ( time & 0x07E0 ) >> 5, ( time & 0x001F ) << 1 ); | |
return tstr; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* FTP SERVER FOR ESP8266 | |
* based on FTP Serveur for Arduino Due and Ethernet shield (W5100) or WIZ820io (W5200) | |
* based on Jean-Michel Gallego's work | |
* modified to work with esp8266 SPIFFS by David Paiva (david@nailbuster.com) | |
* | |
* This program is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation, either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
// 2017: modified by @robo8080 | |
// 2019: modified by @HenrikSte | |
/******************************************************************************* | |
** ** | |
** DEFINITIONS FOR FTP SERVER ** | |
** ** | |
*******************************************************************************/ | |
// Uncomment to print debugging info to console attached to ESP8266 | |
//#define FTP_DEBUG | |
#ifndef FTP_SERVERESP_H | |
#define FTP_SERVERESP_H | |
//#include "Streaming.h" | |
#include "SD.h" | |
#include <FS.h> | |
#include <WiFiClient.h> | |
#define FTP_SERVER_VERSION "FTP-2016-01-14" | |
#define FTP_CTRL_PORT 21 // Command port on wich server is listening | |
#define FTP_DATA_PORT_PASV 50009 // Data port in passive mode | |
#define FTP_TIME_OUT 5 // Disconnect client after 5 minutes of inactivity | |
#define FTP_CMD_SIZE 255 + 8 // max size of a command | |
#define FTP_CWD_SIZE 255 + 8 // max size of a directory name | |
#define FTP_FIL_SIZE 255 // max size of a file name | |
#define FTP_BUF_SIZE (8192*1)-1 //512 // size of file buffer for read/write | |
class FtpServer | |
{ | |
public: | |
FtpServer(); | |
void begin(String uname, String pword); | |
int handleFTP(); | |
private: | |
void iniVariables(); | |
void clientConnected(); | |
void disconnectClient(); | |
boolean userIdentity(); | |
boolean userPassword(); | |
boolean processCommand(); | |
boolean dataConnect(); | |
boolean doRetrieve(); | |
boolean doStore(); | |
void closeTransfer(); | |
void abortTransfer(); | |
boolean makePath( char * fullname ); | |
boolean makePath( char * fullName, char * param ); | |
uint8_t getDateTime( uint16_t * pyear, uint8_t * pmonth, uint8_t * pday, | |
uint8_t * phour, uint8_t * pminute, uint8_t * second ); | |
char * makeDateTimeStr( char * tstr, uint16_t date, uint16_t time ); | |
int8_t readChar(); | |
IPAddress dataIp; // IP address of client for data | |
WiFiClient client; | |
WiFiClient data; | |
File file; | |
boolean dataPassiveConn; | |
uint16_t dataPort; | |
char buf[ FTP_BUF_SIZE ]; // data buffer for transfers | |
char cmdLine[ FTP_CMD_SIZE ]; // where to store incoming char from client | |
char cwdName[ FTP_CWD_SIZE ]; // name of current directory | |
char command[ 5 ]; // command sent by client | |
boolean rnfrCmd; // previous command was RNFR | |
char * parameters; // point to begin of parameters sent by client | |
uint16_t iCL; // pointer to cmdLine next incoming char | |
int8_t cmdStatus, // status of ftp command connexion | |
transferStatus; // status of ftp data transfer | |
uint32_t millisTimeOut, // disconnect after 5 min of inactivity | |
millisDelay, | |
millisEndConnection, // | |
millisBeginTrans, // store time of beginning of a transaction | |
bytesTransfered; // | |
String _FTP_USER; | |
String _FTP_PASS; | |
}; | |
#endif // FTP_SERVERESP_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Carlos Almeida - 2200913 | |
IPLEIRIA - Instituto Politécnico de Leiria | |
ESTG - Escola Superior de Tecnologia e Gestão | |
This project's code can be found in : | |
https://youtu.be/nAdJu2HUppY | |
*/ | |
#include "Arduino.h" | |
#include <stdio.h> | |
#include "freertos/FreeRTOS.h" | |
#include "freertos/task.h" | |
#include "esp_system.h" | |
#include "nvs_flash.h" | |
#include "esp_task_wdt.h" | |
#include "Arduino.h" | |
#include <math.h> | |
#include <SPI.h> | |
#include <Wire.h> | |
#include <Adafruit_GFX.h> | |
#include <Adafruit_SSD1306.h> | |
#include <driver/i2s.h> | |
#include <exception> | |
#include <OLED_SSD1306_Chart.h> | |
#include "driver/i2c.h" | |
#include "esp_freertos_hooks.h" | |
#define I2S_WS 32 | |
#define I2S_SD 33 | |
#define I2S_SCK 26 | |
#define ADC_1_0 4 | |
#define ADC_RESOLUTION 12 | |
#define ADC_RESOLUTION_2 4096.0 | |
#define VREF_PLUS 3.3 | |
#define VREF_MINUS 0.0 | |
#define LED_PIN 5 | |
#define I2S_PORT I2S_NUM_0 | |
#define bufferLen 512 | |
#define PIN_LM35 34 // ESP32 pin GIOP36 (ADC0) connected to LM35 | |
#define ADC_VREF_mV 3300.0 // in millivolt | |
int freq = 5000; | |
int ledChannel = 5; | |
int resolution = 8; | |
//------------------------------------------ | |
//-----------------DISPLAY------------------ | |
//------------------------------------------ | |
#define SCREEN_WIDTH 128 // OLED display width, in pixels | |
#define SCREEN_HEIGHT 64 // OLED display height, in pixels | |
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) | |
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) | |
OLED_SSD1306_Chart display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); | |
#define LOGO_HEIGHT 64 | |
#define LOGO_WIDTH 128 | |
volatile unsigned long ulIdleCycleCount = 0UL; | |
unsigned long lastInterruptTime = 0; | |
//------------------------------------------ | |
//--------------------WIFI------------------ | |
//------------------------------------------ | |
#include <WiFi.h> | |
#include <NTPClient.h> | |
const char *ssid = "BuenosDias"; | |
const char *password = "NaoSeiAPass"; | |
WiFiUDP ntpUDP; | |
NTPClient timeClient(ntpUDP); | |
//------------------------------------------ | |
//---------------------SD CARD------------- | |
//------------------------------------------ | |
#include "FS.h" | |
#include "SD.h" | |
#include "SPI.h" | |
void listDir(fs::FS &fs, const char *dirname, uint8_t levels) { | |
Serial.printf("Listing directory: %s\n", dirname); | |
File root = fs.open(dirname); | |
if (!root) { | |
Serial.println("Failed to open directory"); | |
return; | |
} | |
if (!root.isDirectory()) { | |
Serial.println("Not a directory"); | |
return; | |
} | |
File file = root.openNextFile(); | |
while (file) { | |
if (file.isDirectory()) { | |
Serial.print(" DIR : "); | |
Serial.println(file.name()); | |
if (levels) { | |
listDir(fs, file.name(), levels - 1); | |
} | |
} else { | |
Serial.print(" FILE: "); | |
Serial.print(file.name()); | |
Serial.print(" SIZE: "); | |
Serial.println(file.size()); | |
} | |
file = root.openNextFile(); | |
} | |
} | |
void createDir(fs::FS &fs, const char *path) { | |
Serial.printf("Creating Dir: %s\n", path); | |
if (fs.mkdir(path)) { | |
Serial.println("Dir created"); | |
} else { | |
Serial.println("mkdir failed"); | |
} | |
} | |
void removeDir(fs::FS &fs, const char *path) { | |
Serial.printf("Removing Dir: %s\n", path); | |
if (fs.rmdir(path)) { | |
Serial.println("Dir removed"); | |
} else { | |
Serial.println("rmdir failed"); | |
} | |
} | |
void readFile(fs::FS &fs, const char *path) { | |
Serial.printf("Reading file: %s\n", path); | |
File file = fs.open(path); | |
if (!file) { | |
Serial.println("Failed to open file for reading"); | |
return; | |
} | |
Serial.print("Read from file: "); | |
while (file.available()) { | |
Serial.write(file.read()); | |
} | |
file.close(); | |
} | |
void writeFile(fs::FS &fs, const char *path, const char *message) { | |
Serial.printf("Writing file: %s\n", path); | |
File file = fs.open(path, FILE_WRITE); | |
if (!file) { | |
Serial.println("Failed to open file for writing"); | |
return; | |
} | |
if (file.print(message)) { | |
Serial.println("File written"); | |
} else { | |
Serial.println("Write failed"); | |
} | |
file.close(); | |
} | |
void writeFileAudio(fs::FS &fs, const char *path, const int16_t *buffer, | |
size_t length) { | |
/* Serial.printf("Writing file: %s\n", path);*/ | |
File file = fs.open(path, FILE_APPEND); | |
if (!file) { | |
Serial.println("Failed to open file for writing"); | |
return; | |
} | |
/*if (file.write(buffer,length)) { | |
// Serial.println("File written"); | |
} else { | |
Serial.println("Write failed"); | |
}*/ | |
for (int i = 0; i < length; i++) { | |
file.write((int8_t) (buffer[i] & 0xff)); | |
file.write((int8_t) (buffer[i] >> 8)); | |
} | |
file.close(); | |
} | |
void writeFileAudio_v2(const int16_t *buffer, size_t length) { | |
/* Serial.printf("Writing file: %s\n", path);*/ | |
/* | |
File file = fs.open(path, FILE_APPEND); | |
if (!file) { | |
Serial.println("Failed to open file for writing"); | |
return; | |
} | |
if (file.write(buffer,length*2)) { | |
// Serial.println("File written"); | |
} else { | |
Serial.println("Write failed"); | |
} | |
file.close();*/ | |
FILE *fp; | |
fp = fopen("test_16_bits_data.bin", "ab"); | |
fwrite(buffer, sizeof(int16_t), length, fp); | |
/*if (elements_written != 10) { | |
printf("Failed to write the entire buffer\n"); | |
return 1; | |
}*/ | |
fclose(fp); | |
printf("16 bits data written to file successfully\n"); | |
} | |
void appendFile(fs::FS &fs, const char *path, const char *message) { | |
/* Serial.printf("Appending to file: %s\n", path);*/ | |
/*String message_2="Appending to file:"+String(path)+"\n"; | |
const char *pcMessageToPrint=message_2.c_str(); | |
xQueueSendToBack( xPrintQueue, &( pcMessageToPrint), 0 ); | |
*/ | |
File file = fs.open(path, FILE_APPEND); | |
if (!file) { | |
/*String message_2="Failed to open file for appending\n"; | |
const char *pcMessageToPrint=message_2.c_str(); | |
xQueueSendToBack( xPrintQueue, &( pcMessageToPrint), 0 );*/ | |
/* Serial.println("Failed to open file for appending");*/ | |
return; | |
} | |
if (file.print(message)) { | |
/*String message_2="Message appended\n"; | |
const char *pcMessageToPrint=message_2.c_str(); | |
xQueueSendToBack( xPrintQueue, &( pcMessageToPrint), 0 );*/ | |
/* Serial.println("Message appended");*/ | |
} else { | |
/*String message_2="Append failed\n"; | |
const char *pcMessageToPrint=message_2.c_str(); | |
xQueueSendToBack( xPrintQueue, &( pcMessageToPrint), 0 );*/ | |
/* Serial.println("Append failed");*/ | |
} | |
file.close(); | |
} | |
void renameFile(fs::FS &fs, const char *path1, const char *path2) { | |
Serial.printf("Renaming file %s to %s\n", path1, path2); | |
if (fs.rename(path1, path2)) { | |
Serial.println("File renamed"); | |
} else { | |
Serial.println("Rename failed"); | |
} | |
} | |
void deleteFile(fs::FS &fs, const char *path) { | |
Serial.printf("Deleting file: %s\n", path); | |
if (fs.remove(path)) { | |
Serial.println("File deleted"); | |
} else { | |
Serial.println("Delete failed"); | |
} | |
} | |
void testFileIO(fs::FS &fs, const char *path) { | |
File file = fs.open(path); | |
static uint8_t buf[512]; | |
size_t len = 0; | |
uint32_t start = millis(); | |
uint32_t end = start; | |
if (file) { | |
len = file.size(); | |
size_t flen = len; | |
start = millis(); | |
while (len) { | |
size_t toRead = len; | |
if (toRead > 512) { | |
toRead = 512; | |
} | |
file.read(buf, toRead); | |
len -= toRead; | |
} | |
end = millis() - start; | |
Serial.printf("%u bytes read for %u ms\n", flen, end); | |
file.close(); | |
} else { | |
Serial.println("Failed to open file for reading"); | |
} | |
file = fs.open(path, FILE_WRITE); | |
if (!file) { | |
Serial.println("Failed to open file for writing"); | |
return; | |
} | |
size_t i; | |
start = millis(); | |
for (i = 0; i < 2048; i++) { | |
file.write(buf, 512); | |
} | |
end = millis() - start; | |
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end); | |
file.close(); | |
} | |
String testFileIO_String(fs::FS &fs, const char *path) { | |
File file = fs.open(path); | |
static uint8_t buf[512]; | |
size_t len = 0; | |
uint32_t start = millis(); | |
uint32_t end = start; | |
if (file) { | |
len = file.size(); | |
size_t flen = len; | |
start = millis(); | |
while (len) { | |
size_t toRead = len; | |
if (toRead > 512) { | |
toRead = 512; | |
} | |
file.read(buf, toRead); | |
len -= toRead; | |
} | |
end = millis() - start; | |
return String(flen); | |
/*Serial.printf("%u bytes read for %u ms\n", flen, end);*/ | |
file.close(); | |
} else { | |
/*Serial.println("Failed to open file for reading");*/ | |
} | |
return "nothing"; | |
/* | |
file = fs.open(path, FILE_WRITE); | |
if (!file) { | |
Serial.println("Failed to open file for writing"); | |
return "Failed to open file for writing"; | |
} | |
size_t i; | |
start = millis(); | |
for (i = 0; i < 2048; i++) { | |
file.write(buf, 512); | |
} | |
end = millis() - start; | |
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end); | |
file.close();*/ | |
} | |
//------------------------------------------ | |
//-------------FREE RTOS-------------------- | |
//------------------------------------------ | |
void vTaskADC(void *pvParameters); | |
void vTaskLED(void *pvParameters); | |
void vTaskDisplay(void *pvParameters); | |
void vTaskWriteDataSD(void *pvParameters); | |
void vTaskServerFTP(void *pvParameters); | |
void vTaskCpuUsage(void *pvParameters); | |
void vTaskTime(void *pvParameters); | |
void vTaskAudio(void *pvParameters); | |
//Gatekeeper for the serial | |
static void vGatekeeperTaskSerial( void *pvParameters ); | |
/* The service routine for the interrupt. This is the interrupt that the task | |
will be synchronized with. */ | |
static void IRAM_ATTR vButtonInterruptHandler(void); | |
const char *pcTextForADC = "ADC is running\r\n"; | |
const char *pcTextForPWM = "PWM is running\t\n"; | |
const char *pcTextTime = "Time is adquiring\t\n"; | |
const char *pcTextShowData = "Data acquired is being shown\t\n"; | |
const char *pcTextWriteData = "Data acquired is being written\t\n"; | |
QueueHandle_t xQueueSETPOINT_TEMP; | |
QueueHandle_t xQueueSETPOINT_TIME; | |
QueueHandle_t xQueueSETPOINT_DAY; | |
QueueHandle_t xQueueSETPOINT_AUDIO_MEAN; | |
QueueHandle_t xQueueSETPOINT_CPU_USAGE; | |
QueueHandle_t xPrintQueue; | |
QueueHandle_t xQueueSize; | |
SemaphoreHandle_t xBinarySemaphore_ResetGraphAtStart; | |
SemaphoreHandle_t xCountingSemaphore; | |
const uint8_t interruptPin = 2; | |
/* Used to hold the handle of Task2. */ | |
TaskHandle_t xTaskAudioHandle; | |
TaskHandle_t xTaskPWMHandle; | |
// Tempo da última interruption (Debounce Circuit) | |
TickType_t xLastIntTime; | |
//Mutex for sd card usage | |
SemaphoreHandle_t xMutex_SD_CARD; | |
//-------------------------------------- | |
//---------------MICROFONE------------- | |
//-------------------------------------- | |
#include <driver/i2s.h> | |
#include <exception> | |
#define I2S_WS 32 | |
#define I2S_SD 33 | |
#define I2S_SCK 26 | |
#define I2S_PORT I2S_NUM_0 | |
#define bufferLen 512*2 | |
// The I2S microphone's sample rate, bits per sample, and number of channels | |
const int sample_rate = 16000; | |
const int bits_per_sample = 16; | |
const int num_channels = 1; | |
void i2s_install() { | |
const i2s_config_t i2s_config = { .mode = i2s_mode_t( | |
I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX), .sample_rate = 16000, | |
.bits_per_sample = i2s_bits_per_sample_t(16), .channel_format = | |
I2S_CHANNEL_FMT_ONLY_LEFT, | |
//.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_MSB), | |
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S), | |
.intr_alloc_flags = 0, // default interrupt priority | |
//.dma_buf_count = 16, | |
.dma_buf_count = 10, .dma_buf_len = bufferLen, .use_apll = false, | |
.tx_desc_auto_clear = false, .fixed_mclk = -1, }; | |
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); | |
} | |
void i2s_setpin() { | |
const i2s_pin_config_t pin_config = { .bck_io_num = I2S_SCK, .ws_io_num = | |
I2S_WS, .data_out_num = -1, .data_in_num = I2S_SD }; | |
i2s_set_pin(I2S_PORT, &pin_config); | |
} | |
//-------------------------------------- | |
//---------------WEB SERVER------------- | |
//-------------------------------------- | |
#include "ESP32FtpServer.h" | |
FtpServer ftpSrv; //set #define FTP_DEBUG in ESP8266FtpServer.h to see ftp verbose on serial | |
void setup(void) { | |
Serial.begin(115200); | |
Serial.println("\nEU vou iniciar!"); | |
//------------------------------------------------ | |
//--------------------DISPLAY--------------------- | |
//------------------------------------------------ | |
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { | |
Serial.println(F("SSD1306 allocation failed")); | |
for (;;) | |
; // Don't proceed, loop forever | |
} | |
display.clearDisplay(); | |
vTaskDelay(10); | |
display.setCursor(0, 0); | |
display.setTextSize(2); | |
display.setTextColor(WHITE); | |
// Display static text | |
display.println(" AUDIO"); | |
display.println(" &"); | |
display.println(" DATA"); | |
display.println(" RECORDER"); | |
vTaskDelay(10); | |
display.setCursor(0, 10); | |
vTaskDelay(10); | |
vTaskDelay(10); | |
display.display(); | |
//------------------------------------------------ | |
//-----------------------WI-FI------------------- | |
//------------------------------------------------ | |
Serial.println("\nEU vou configurar a net"); | |
WiFi.begin(ssid, password); | |
vTaskDelay(2000); | |
while (WiFi.status() != WL_CONNECTED) { | |
vTaskDelay(3000); | |
Serial.println("Connecting to WiFi..."); | |
WiFi.begin(ssid, password); | |
} | |
timeClient.begin(); | |
vTaskDelay(100); | |
timeClient.update(); | |
Serial.println(timeClient.getFormattedTime()); | |
//------------------------------------------------ | |
//-----------------SD CARD---------------------- | |
//------------------------------------------------ | |
do { | |
Serial.println("Card Mount Failed"); | |
vTaskDelay(500); | |
} while (!SD.begin(5)); | |
uint8_t cardType = SD.cardType(); | |
if (cardType == CARD_NONE) { | |
Serial.println("No SD card attached"); | |
return; | |
} | |
Serial.print("SD Card Type: "); | |
if (cardType == CARD_MMC) { | |
Serial.println("MMC"); | |
} else if (cardType == CARD_SD) { | |
Serial.println("SDSC"); | |
} else if (cardType == CARD_SDHC) { | |
Serial.println("SDHC"); | |
} else { | |
Serial.println("UNKNOWN"); | |
} | |
uint64_t cardSize = SD.cardSize() / (1024 * 1024); | |
Serial.printf("SD Card Size: %lluMB\n", cardSize); | |
listDir(SD, "/", 0); | |
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024)); | |
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024)); | |
ftpSrv.begin("esp32","esp32"); //username, password for ftp. set ports in ESP8266FtpServer.h (default 21, 50009 for PASV) | |
//------------------------------------------------ | |
//-----------------I2S MICROPHONE----------------- | |
//------------------------------------------------ | |
Serial.println("Setup I2S ..."); | |
vTaskDelay(1000); | |
i2s_install(); | |
i2s_setpin(); | |
i2s_start(I2S_PORT); | |
vTaskDelay(500); | |
//AUDIO DIR | |
createDir(SD, "/audio_recording"); | |
writeFile(SD, "/audio_recording/hello.txt", "Hello "); | |
//------------------------------------------------ | |
//-------------------FREE RTOS START------------- | |
//------------------------------------------------ | |
//TASKS | |
//QUEUES | |
//INTERRUPTS | |
//------------------------------------------------ | |
vTaskPrioritySet(NULL, configMAX_PRIORITIES - 1); | |
vSemaphoreCreateBinary(xBinarySemaphore_ResetGraphAtStart); | |
xCountingSemaphore = xSemaphoreCreateCounting(2, 0); | |
pinMode(digitalPinToInterrupt(interruptPin), INPUT_PULLUP); | |
attachInterrupt(digitalPinToInterrupt(interruptPin), | |
&vButtonInterruptHandler, FALLING); | |
xTaskCreatePinnedToCore(vTaskADC, "ADC", 2*1024, (void*) pcTextForADC, 3, | |
NULL, 1); | |
xTaskCreatePinnedToCore(vTaskCpuUsage, "CPU", 2*1024, (void*) pcTextForADC, 7, | |
NULL, 1); | |
xTaskCreatePinnedToCore(vTaskServerFTP, "FTP", 15*1024, (void*) pcTextForADC, 1, | |
NULL, 1); | |
xTaskCreatePinnedToCore(vTaskLED, "LED", 1024, (void*) pcTextForPWM, 5, | |
&xTaskPWMHandle, 1); | |
xTaskCreatePinnedToCore(vTaskDisplay, "Display", 4 * 1024, | |
(void*) pcTextShowData, 6, NULL, 1); | |
xTaskCreatePinnedToCore(vTaskWriteDataSD, "WriteData", 4 * 1024, | |
(void*) pcTextShowData, 4, NULL, 1); | |
xTaskCreatePinnedToCore(vTaskTime, "Time", 2 * 1024, (void*) pcTextTime, 3, | |
NULL, 1); | |
xTaskCreatePinnedToCore(vTaskAudio, "Audio", 15 * 1024, (void*) pcTextTime, | |
2, &xTaskAudioHandle, 1); | |
//Gatekeeper task | |
xTaskCreate( vGatekeeperTaskSerial, "Gatekeeper", 1024, NULL, 0, NULL ); | |
xPrintQueue = xQueueCreate( 10, sizeof( char * ) ); | |
xQueueSize = xQueueCreate(1, sizeof(String)); | |
xQueueSETPOINT_TEMP = xQueueCreate(1, sizeof(float)); | |
xQueueSETPOINT_TIME = xQueueCreate(1, sizeof(String)); | |
xQueueSETPOINT_DAY = xQueueCreate(1, sizeof(String)); | |
xQueueSETPOINT_AUDIO_MEAN = xQueueCreate(1, sizeof(float)); | |
xQueueSETPOINT_CPU_USAGE = xQueueCreate(1, sizeof(int)); | |
xLastIntTime = xTaskGetTickCount(); | |
xMutex_SD_CARD = xSemaphoreCreateMutex(); | |
esp_register_freertos_idle_hook(my_vApplicationIdleHook); | |
//------------------------------------------------ | |
//--------------------PWM START------------------- | |
//------------------------------------------------ | |
ledcSetup(ledChannel, freq, resolution); | |
ledcAttachPin(LED_PIN, ledChannel); | |
//------------------------------------------------ | |
//-------------------SEMAPHORE INITIAL TAKE------- | |
//------------------------------------------------ | |
xSemaphoreTake(xCountingSemaphore, portMAX_DELAY); | |
} | |
/*Lê o valor analógico do sensor de temperatura LM35, coloca-o na queue | |
xQueueSETPOINT_TEMP e coloca também a mensagem a mostrar na porta Serial na queue | |
xPrintQueue */ | |
void vTaskADC(void *pvParameters) { | |
char *pcTaskName; | |
TickType_t xLastWakeTime; | |
int analog_value = 0; | |
float milliVolt = 0; | |
float tempC = 0; | |
pcTaskName = (char*) pvParameters; | |
analogReadResolution(ADC_RESOLUTION); | |
xLastWakeTime = xTaskGetTickCount(); | |
for (;;) { | |
analog_value = analogRead(PIN_LM35); | |
// convert the ADC value to voltage in millivolt | |
milliVolt = analog_value * (ADC_VREF_mV / ADC_RESOLUTION_2); | |
// convert the voltage to the temperature in °C | |
tempC = milliVolt/10; | |
//tempC = milliVolt /10; | |
xQueueOverwrite(xQueueSETPOINT_TEMP, &tempC); | |
String message="ADC value: "+String(analog_value)+" Temperatura: "+String(tempC)+"\n"; | |
const char *pcMessageToPrint=message.c_str(); | |
xQueueSendToBack( xPrintQueue, &( pcMessageToPrint), 0 ); | |
vTaskDelayUntil(&xLastWakeTime, (500 / portTICK_PERIOD_MS)); | |
} | |
} | |
/*Verifica a hora e dia atual consultando um servidor NTP , coloca a hora e o dia nas queues | |
* xQueueSETPOINT_TIME e xQueueSETPOINT_DAY respectivamente e coloca também a mensagem a transmitir | |
* na porta Serial na queue xPrintQueue*/ | |
void vTaskTime(void *pvParameters) { | |
char *pcTaskName; | |
TickType_t xLastWakeTime; | |
String time; | |
String day; | |
pcTaskName = (char*) pvParameters; | |
analogReadResolution(ADC_RESOLUTION); | |
xLastWakeTime = xTaskGetTickCount(); | |
for (;;) { | |
/* Serial.print(pcTaskName);*/ | |
timeClient.update(); | |
time = timeClient.getFormattedTime(); | |
day = String(timeClient.getDay()); | |
String message="Day: "+day+" Hours :"+time+"\n"; | |
const char *pcMessageToPrint=message.c_str(); | |
xQueueSendToBack( xPrintQueue, &( pcMessageToPrint), 0 ); | |
xQueueOverwrite(xQueueSETPOINT_TIME, &time); | |
xQueueOverwrite(xQueueSETPOINT_DAY, &day); | |
vTaskDelayUntil(&xLastWakeTime, (5000 / portTICK_PERIOD_MS)); | |
} | |
} | |
/*Esta tarefa controla o LED, normalmente liga-o normalmente e quando o audio está a gravar no cartão SD | |
controla a intensidade do LED com um sinal PWM baseado no valor de audio atual, para tal vai consultar o | |
semáforo contador xCountingSemaphore , a queue xQueueSETPOINT_AUDIO_MEAN e transmite a sua mensagem | |
a mostrar na porta Serial para a queue xPrintQueue*/ | |
void vTaskLED(void *pvParameters) { | |
char *pcTaskName; | |
TickType_t xLastWakeTime; | |
int freq = 5000; | |
int ledChannel = 5; | |
int resolution = 10; | |
int dutyCycle = 0; | |
pcTaskName = (char*) pvParameters; | |
ledcSetup(ledChannel, freq, resolution); | |
ledcAttachPin(LED_PIN, ledChannel); | |
xLastWakeTime = xTaskGetTickCount(); | |
float mean; | |
for (;;) { | |
xQueuePeek(xQueueSETPOINT_AUDIO_MEAN, &mean, (500 / portTICK_PERIOD_MS)); | |
String message="Audio mean from PWM is"+String(mean)+"\n"; | |
const char *pcMessageToPrint=message.c_str(); | |
xQueueSendToBack( xPrintQueue, &( pcMessageToPrint), 0 ); | |
if(mean<0){ | |
mean=25; | |
} | |
if(mean>1024) | |
{ | |
mean=1024; | |
} | |
if (uxSemaphoreGetCount(xCountingSemaphore) == 1) { | |
for (int dutyCycle = 0; dutyCycle <= mean; | |
dutyCycle++) { | |
ledcWrite(ledChannel, dutyCycle); | |
vTaskDelay(1024 / mean); | |
} | |
for (int dutyCycle = mean; dutyCycle >= 0; | |
dutyCycle--) { | |
ledcWrite(ledChannel, dutyCycle); | |
vTaskDelay(1024 / mean); | |
} | |
} else { | |
ledcWrite(ledChannel, pow(2, resolution)); | |
} | |
vTaskDelayUntil(&xLastWakeTime, (2000 / portTICK_PERIOD_MS)); | |
} | |
} | |
/*Esta tarefa não faz uso de nenhum vtaskDelayUntil pois a leitura do áudio em si já | |
faz um delay até o buffer estiver cheio (neste caso 30ms). Está constantemente a adquirir | |
áudio, quando o semáforo contador chega ao seu primeiro incremento começa a gravar o | |
audio em pedaços de 30 ms no cartão SD. | |
O nome com que grava é dependente do dia/hora atual que vai consultar ás respetivas | |
queues e a gravação do audio na sua respetiva queue. O acesso ao cartão SD é controlado | |
através de um mutex xMutex_SD_CARD. | |
Quando esta tarefa está a gravar aumenta a sua própria prioridade de modo a evitar | |
interrupções não pretendidas, aumenta também a prioridade da tarefa vTaskLED para | |
que o LED continue a ter a sua intensidade variada com o audio. | |
Após ter sido terminada a gravação, é feito o give ao semáforo xBinarySemaphore_Rese- | |
tGraphAtStart para re-iniciar o gráfico no display*/ | |
void vTaskAudio(void *pvParameters) { | |
static portBASE_TYPE run; | |
int16_t sBuffer[bufferLen]; | |
String path; | |
unsigned portBASE_TYPE uxPriority; | |
unsigned portBASE_TYPE uxPriorityPWM; | |
String time; | |
String day; | |
String size ="0"; | |
uxPriority = uxTaskPriorityGet( NULL); | |
uxPriorityPWM = uxTaskPriorityGet( xTaskPWMHandle); | |
for (;;) { | |
size_t bytesIn = 0; | |
esp_err_t result = i2s_read(I2S_PORT, &sBuffer, bufferLen, &bytesIn, | |
portMAX_DELAY); | |
if (result == ESP_OK) { | |
int samples_read = bytesIn / 8; | |
if (samples_read > 0) { | |
float mean = 0; | |
for (int i = 0; i < bytesIn; ++i) { | |
sBuffer[i] = sBuffer[i] * 2; | |
if(sBuffer[i]>0){ | |
mean += (sBuffer[i]); | |
} | |
} | |
mean /= samples_read; | |
xQueueOverwrite(xQueueSETPOINT_AUDIO_MEAN, &mean); | |
time.replace(":","_"); | |
//SEMAPHORE FOR BUTTON AND PROXIMITY SENSOR | |
if (uxSemaphoreGetCount(xCountingSemaphore) == 1) { | |
path = "/audio_recording/test" + day+"_"+time | |
+ ".raw"; | |
//RAISING THE PRIORITY OF THIS TASK | |
//when writing audio on sd card | |
vTaskPrioritySet(xTaskAudioHandle, (uxPriority + 10)); | |
vTaskPrioritySet(xTaskPWMHandle, (uxPriority + 11)); | |
//MUTEX TO PROTECT THE USE OF SD CARD | |
xSemaphoreTake( xMutex_SD_CARD, portMAX_DELAY ); | |
{ | |
writeFileAudio(SD, path.c_str(), sBuffer, bufferLen); | |
} | |
xSemaphoreGive( xMutex_SD_CARD ); | |
//Reseting the priority back to normal | |
vTaskPrioritySet(xTaskAudioHandle, (uxPriority)); | |
vTaskPrioritySet(xTaskPWMHandle, (uxPriorityPWM)); | |
}else{ | |
xQueuePeek(xQueueSETPOINT_TIME, &time, 0); | |
xQueuePeek(xQueueSETPOINT_DAY, &day, 0); | |
} | |
if (uxSemaphoreGetCount(xCountingSemaphore) == 2) { | |
//Counting semaphore reset | |
xSemaphoreTake( xMutex_SD_CARD, portMAX_DELAY ); | |
{ | |
size = testFileIO_String(SD,path.c_str()); | |
} | |
xSemaphoreGive( xMutex_SD_CARD ); | |
xQueueOverwrite(xQueueSize, &size); | |
vTaskDelay(3000/ portTICK_PERIOD_MS); | |
vSemaphoreDelete(xCountingSemaphore); | |
xCountingSemaphore = xSemaphoreCreateCounting(2, 0); | |
xSemaphoreGive(xBinarySemaphore_ResetGraphAtStart); | |
} | |
} | |
} | |
/* ftpSrv.handleFTP();*/ | |
} | |
} | |
/*Lé os dados a guardar no cartão SD, sendo eles a temperatura, hora , dia e utilização do processador das duas respectivas queues. | |
Guarda os dados lidos no cartão SD que tem o acesso controlado pelo mutex xMutex_SD_CARD e retorna uma mensagem para a queue xPrintQueue*/ | |
void vTaskWriteDataSD(void *pvParameters) { | |
TickType_t xLastWakeTime; | |
float temperature; | |
String time; | |
String day; | |
int cpu_usage; | |
String temperature_mandar; | |
for (;;) { | |
xQueueReceive(xQueueSETPOINT_TEMP, &temperature, 0); | |
xQueueReceive(xQueueSETPOINT_TIME, &time, 0); | |
xQueueReceive(xQueueSETPOINT_DAY, &day, 0); | |
xQueueReceive(xQueueSETPOINT_CPU_USAGE,&cpu_usage,0); | |
temperature_mandar = String(temperature, 2); | |
//WRITING | |
//MUTEX TO PROTECT THE USE OF SD CARD | |
xSemaphoreTake( xMutex_SD_CARD, portMAX_DELAY ); | |
{ | |
appendFile(SD, "/data_from_esp32.txt", "DAY:"); | |
appendFile(SD, "/data_from_esp32.txt", day.c_str()); | |
appendFile(SD, "/data_from_esp32.txt", " HOURS:"); | |
appendFile(SD, "/data_from_esp32.txt", time.c_str()); | |
appendFile(SD, "/data_from_esp32.txt", " DATA:"); | |
appendFile(SD, "/data_from_esp32.txt", temperature_mandar.c_str()); | |
appendFile(SD, "/data_from_esp32.txt", " CPU USAGE:"); | |
appendFile(SD, "/data_from_esp32.txt", (String(cpu_usage)).c_str()); | |
appendFile(SD, "/data_from_esp32.txt", "\n"); | |
} | |
xSemaphoreGive( xMutex_SD_CARD ); | |
String message="Temperature and time written on sd card\n"; | |
const char *pcMessageToPrint=message.c_str(); | |
xQueueSendToBack( xPrintQueue, &( pcMessageToPrint), 0 ); | |
vTaskDelayUntil(&xLastWakeTime, (5000 / portTICK_PERIOD_MS)); | |
} | |
} | |
static void IRAM_ATTR vButtonInterruptHandler(void) { | |
static signed portBASE_TYPE xHigherPriorityTaskWoken; | |
xHigherPriorityTaskWoken = pdFALSE; | |
unsigned long currentTime = millis(); | |
if (currentTime - lastInterruptTime < 200) { | |
return; | |
} | |
lastInterruptTime = currentTime; | |
/*Give to a counting semaphore */ | |
xSemaphoreGiveFromISR(xCountingSemaphore, | |
(BaseType_t* )&xHigherPriorityTaskWoken); | |
if (xHigherPriorityTaskWoken == pdTRUE) { | |
/* Giving the semaphore unblocked a task, and the priority of the | |
unblocked task is higher than the currently running task - force | |
a context switch to ensure that the interrupt returns directly to | |
the unblocked (higher priority) task. | |
NOTE: The syntax for forcing a context switch is different depending | |
on the port being used. Refer to the examples for the port you are | |
using for the correct method to use! */ | |
portYIELD_FROM_ISR(); | |
// vPortYield(); | |
} | |
} | |
/*É a única tarefa que acede ao display, e tem a possibilidade de mostrar 3 ecrãs | |
diferentes. | |
O primeiro ecrã é o seu estado normal, onde mostra a temperatura e hora atual , tanto | |
como um gráfico do audio a ser detetado em tempo real. Para tal acede ás queues xQueue- | |
SETPOINT_TEMP, xQueueSETPOINT_TIME e xQueueSETPOINT_AUDIO_MEAN. | |
O segundo ecrã é mostrado assim que é começada a gravação do áudio, o que é | |
indicado pelo semáforo contador xCountingSemaphore , o segundo ecrã consiste apenas | |
na indicação que o audio está a ser gravado. | |
O terceiro ecrã é mostrado quando for terminada a gravação e mostra o tamanho total | |
do audio gravado, sendo que passados 3 segundos volta ao ecrã inicial*/ | |
void vTaskDisplay(void *pvParameters) { | |
char *pcTaskName; | |
TickType_t xLastWakeTime; | |
float temperature; | |
String time; | |
pcTaskName = (char*) pvParameters; | |
String size_audio; | |
boolean display_once; | |
float mean; | |
xLastWakeTime = xTaskGetTickCount(); | |
char *pcMessageToPrint; | |
static portBASE_TYPE run; | |
//----------------------------------- | |
//DRAWING A CHART FOR THE AUDIO GRAPH | |
//----------------------------------- | |
display.setChartCoordinates(0, 60); //Chart lower left coordinates (X, Y) | |
display.setChartWidthAndHeight(123, 40); //Chart width = 123 and height = 60 | |
display.setXIncrement(5); //Distance between Y points will be 5px | |
display.setYLimits(0, 1000); //Ymin = 0 and Ymax = 100 | |
display.setYLimitLabels("0", "1000"); //Setting Y axis labels | |
display.setYLabelsVisible(true); | |
display.setAxisDivisionsInc(12, 6); //Each 12 px a division will be painted in X axis and each 6px in Y axis | |
display.setPlotMode(SINGLE_PLOT_MODE); //Set single plot mode | |
display.setPointGeometry(POINT_GEOMETRY_NONE); | |
display.setLineThickness(LIGHT_LINE); | |
init_graph_com_valores(String(temperature),time); | |
for (;;) { | |
xQueuePeek(xQueueSETPOINT_TEMP, &temperature, 0); | |
xQueuePeek(xQueueSETPOINT_TIME, &time, 0); | |
xQueueReceive(xQueueSize, &size_audio, 0); | |
String message="Current semaphore counter is : "+String(uxSemaphoreGetCount(xCountingSemaphore))+"\n"; | |
const char *pcMessageToPrint=message.c_str(); | |
xQueueSendToBack( xPrintQueue, &( pcMessageToPrint), 0 ); | |
if (uxSemaphoreGetCount(xCountingSemaphore) == 0) { | |
xQueuePeek(xQueueSETPOINT_AUDIO_MEAN, &mean, 0); | |
run= xSemaphoreTake( xBinarySemaphore_ResetGraphAtStart, (100 / portTICK_PERIOD_MS) ); | |
if(run==pdPASS){ | |
init_graph_com_valores(String(temperature),time); | |
} | |
if (!display.updateChart(mean)) //Value between Ymin and Ymax will be added to chart | |
{ | |
init_graph_com_valores(String(temperature),time); | |
} | |
display_once = true; | |
} | |
if (uxSemaphoreGetCount(xCountingSemaphore) == 1) { | |
//Display only once because the audio acquisition is a continuous function | |
//So the processor will always be busy on that higher priority task | |
if (display_once == true) { | |
display.clearDisplay(); | |
display.setCursor(0, 0); | |
display.setTextSize(2); | |
display.setTextColor(WHITE); | |
// Display static text | |
display.println(" AUDIO "); | |
vTaskDelay(50 / portTICK_PERIOD_MS); | |
display.println("RECORDING"); | |
display.display(); | |
display_once = false; | |
} | |
} | |
if (uxSemaphoreGetCount(xCountingSemaphore) == 2) { | |
display.clearDisplay(); //If chart is full, it is drawn again | |
display.setCursor(0, 0); | |
display.setTextSize(2); | |
display.setTextColor(WHITE); | |
vTaskDelay(100/portTICK_PERIOD_MS); | |
// Display static text | |
display.println("Audio has:"); | |
vTaskDelay(50 / portTICK_PERIOD_MS); | |
display.println(size_audio); | |
display.println(" bytes"); | |
display.display(); | |
} | |
vTaskDelayUntil(&xLastWakeTime, (500 / portTICK_PERIOD_MS)); | |
} | |
} | |
/*Esta tarefa controla a porta Serial, sendo a única tarefa que lhe acede. Todas as outras | |
tarefas quando querem mostrar algo na porta Serial, mandam a mensagem para a queue | |
xPrintQueue que é lida por esta tarefa, ao ler uma mensagem com sucesso transmite-a | |
para a porta Serial*/ | |
static void vGatekeeperTaskSerial( void *pvParameters ) | |
{ | |
char *pcMessageToPrint; | |
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; | |
for( ;; ) | |
{ | |
/* Wait for a message to arrive. */ | |
xQueueReceive( xPrintQueue, &pcMessageToPrint, portMAX_DELAY ); | |
/* There is no need to check the return value as the task will block | |
indefinitely and only run again when a message has arrived. When the | |
next line is executed there will be a message to be output. */ | |
vTaskEnterCritical(&mux); | |
Serial.print(pcMessageToPrint ); | |
Serial.flush(); | |
vTaskExitCritical(&mux); | |
if (Serial.available()) { | |
vTaskEndScheduler(); | |
} | |
/* Now simply go back to wait for the next message. */ | |
} | |
} | |
/*Função auxiliar com o propósito de não re-escrever código, sendo que é usada várias vezes. | |
coloca os valores iniciais de temperatura, hora e desenha o gráfico*/ | |
void init_graph_com_valores(String valor_recb_temp, String hora){ | |
//----------------------------------- | |
//DISPLAYING DATA INITIALLY | |
//----------------------------------- | |
display.clearDisplay(); | |
display.setCursor(0, 0); | |
display.setTextSize(1); | |
display.setTextColor(WHITE); | |
// Display static text | |
display.println("Temperature | Time"); | |
display.print(valor_recb_temp); | |
display.print(" C |"); | |
display.println(hora); | |
display.drawChart(); //Update the buffer to draw the cartesian chart | |
display.display(); | |
} | |
/*Esta tarefa é o que controla os pedidos ao servidor FTP, tal como o pedido de ler o que está dentro do diretório ou | |
fazer download/upload de um ficheiro*/ | |
void vTaskServerFTP(void *pvParameters){ | |
TickType_t xLastWakeTime; | |
xLastWakeTime = xTaskGetTickCount(); | |
for (;;){ | |
ftpSrv.handleFTP(); //make sure in loop you call handleFTP()!! | |
vTaskDelayUntil(&xLastWakeTime, (100 / (portTICK_PERIOD_MS))); | |
} | |
} | |
/*Esta tarefa lê o contador de ciclos em idle que é incrementado sempre que o pro- | |
cessador fica em Idle, com esse contador calcula a utilização do processador. Transmite | |
o valor calculado para a queue xQueueSETPOINT_CPU_USAGE e transmite também | |
uma mensagem para a queue xPrintQueue para ser mostrada na porta Serial pelo gate- | |
keeper*/ | |
void vTaskCpuUsage(void *pvParameters){ | |
TickType_t xLastWakeTime; | |
xLastWakeTime = xTaskGetTickCount(); | |
int cpu_usage; | |
int ciclos; | |
int ciclos_totais; | |
for (;;){ | |
ciclos=ulIdleCycleCount; | |
//1.15 because it was noted that even if this task has a periodicity of 1 second, it takes around 1.15 seconds to repeat itself | |
ciclos_totais = (1.15) * configTICK_RATE_HZ; | |
cpu_usage=(100-((ciclos*100)/ciclos_totais)); | |
String message="Ciclos: "+String(ciclos)+" Ciclos totais: "+String(ciclos_totais)+" Cpu usage "+String(cpu_usage)+"% \n"; | |
const char *pcMessageToPrint=message.c_str(); | |
xQueueSendToBack( xPrintQueue, &( pcMessageToPrint), 0 ); | |
ulIdleCycleCount=0; | |
xQueueOverwrite(xQueueSETPOINT_CPU_USAGE, &cpu_usage); | |
vTaskDelayUntil(&xLastWakeTime, (1000 / (portTICK_PERIOD_MS))); | |
} | |
} | |
/* Idle hook functions MUST be called vApplicationIdleHook(), take no parameters, | |
and return void. */ | |
bool my_vApplicationIdleHook( void ) | |
{ | |
//This method makes it so while on idle, the microprocessor increments a counter. | |
ulIdleCycleCount++; | |
return true; | |
} | |
void loop() { | |
vTaskDelete( NULL); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment