#include "esp_task_wdt.h" //Used by esp_task_wdt_reset()
#define CORE_ZERO 0
#define CORE_ONE 1
//////PCA9548
#define INTERNAL_OLED_I2C_CHANNEL 0
#define INTERNAL_TCA9555_I2C_CHANNEL 5
// include the SD library:
#include <SPI.h>
#include <SD.h>
///////////////
float cardSizeInMB=0;
float spaceAvailableInMB=0;
int BlockNumberinFile = 0;
bool fileAlreaydyOpen = false;
//////////////
#include "RTClib.h"
DateTime DateTimeGlobal;
///////////////////////////////////OLED
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#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)
//////////////////////////
int indice_menu_demande = 0;
//////////////////////SEMAPHORES & MUTEX
SemaphoreHandle_t xMutexSemaphoreBusI2C;
SemaphoreHandle_t xMutexSemaphoreBusSPI;
SemaphoreHandle_t xMutexSemaphoreSDAccess;
SemaphoreHandle_t xMutexSemaphoreDebug;
SemaphoreHandle_t xMutexSemaphoreRTC;
SemaphoreHandle_t xMutexSemaphoreDateTimeRTC;
SemaphoreHandle_t xMutexSemaphoreForMeasurementSHT30;
SemaphoreHandle_t xMutexSemaphoreGlobalVariables;
SemaphoreHandle_t interruptSemaphoreBUTTON;
// WeMos D1 esp8266: D8 as standard
const int chipSelect = 5;
bool initSDdone = false;
bool OledMosfetToSwitchOff = false;
bool OledMosfet = true;
bool initOledDone = false;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define PIN_LED_BLEU 2//23
#define PIN_LED_ROUGE 22
#define PIN_LED_VERTE 21
typedef struct ParamStruct
{
uint32_t arg1;
uint32_t arg2;
uint32_t arg3;
uint32_t arg4;
} ;
void selectI2Cchannel(int channel)
{
return;
}
void ecrire_debug(String string_toprint)
{
Serial.print(string_toprint);
}
////////////////////
#include "DHTesp.h"
const int DHT_PIN = 4;
float dhtHumidityGlobal;
float dhtTemperatureGlobal;
DHTesp dhtSensor;
void TaskDHT(void *pParameters)
{
dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
for (;;)
{
vTaskDelay(500);
TempAndHumidity data = dhtSensor.getTempAndHumidity();
xSemaphoreTake(xMutexSemaphoreGlobalVariables, portMAX_DELAY);
dhtHumidityGlobal = data.humidity;
dhtTemperatureGlobal = data.temperature;
xSemaphoreGive(xMutexSemaphoreGlobalVariables);
}
}
///////////////////
//////////////
int cw = SSD1306_WHITE; // colour white
int cb = SSD1306_BLACK; // colour black
//////////////////////////////////////////////////////////////////////////////////////////////////
void show() { // Often used sequence - Function to simplify code
display.display();
vTaskDelay(2000);
display.fillScreen(SSD1306_BLACK);
}
void display_oled_groove(const char *string_to_display, const char *string_to_display_2, const char *string_to_display_3, const char *string_to_display_4, bool clear_screen) {
if (OledMosfet == false) {
initOledDone = false;
return;
}
if (initOledDone == false) {
xSemaphoreTake(xMutexSemaphoreBusI2C, portMAX_DELAY);
selectI2Cchannel(INTERNAL_OLED_I2C_CHANNEL);
initOledDone = display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
xSemaphoreGive(xMutexSemaphoreBusI2C);
}
if (initOledDone == true) {
xSemaphoreTake(xMutexSemaphoreBusI2C, portMAX_DELAY);
selectI2Cchannel(INTERNAL_OLED_I2C_CHANNEL);
if (clear_screen == true) {
display.clearDisplay(); // clear the internal memory
}
display.setTextSize(4); // Normal 1:1 pixel scale
display.setTextColor(cw);
display.setCursor(0, 0);
display.println("27.5");
/*
if (string_to_display != NULL) {
display.println(string_to_display); // write something to the internal memory
} else
display.println("");
if (string_to_display_2 != NULL) {
display.println(string_to_display_2); // write something to the internal memory
} else
display.println("");
if (string_to_display_3 != NULL) {
// display.setCursor(5, 35);
display.println(string_to_display_3); // write something to the internal memory
} else
display.println("");
if (string_to_display_4 != NULL) {
// display.setCursor(5, 35);
display.println(string_to_display_4); // write something to the internal memory
} else
display.println("");
*/
/*
char string_rtc[100];
sprintf(string_rtc, "PCF8563 : %d:%d:%d", heure_rtc, minute_rtc, seconde_rtc);
//xSemaphoreGive(xMutexSemaphoreBusI2C);
selectI2Cchannel(INTERNAL_OLED_I2C_CHANNEL); //on reselectionne l'OLED
display.println(string_rtc); // write something to the internal memory
char string_esp32[100];
if (wifistate == true)
sprintf(string_esp32, "IP %d.%d.%d.%d", Esp32IPAdress[0], Esp32IPAdress[1], Esp32IPAdress[2], Esp32IPAdress[3]);
else
sprintf(string_esp32, "WIFI OFF...");
display.println(string_esp32); // write something to the internal memory
*/
display.display();
// transfer internal memory to the display
xSemaphoreGive(xMutexSemaphoreBusI2C);
}
}
#define TAILLE_BUFFER_DEBUG 100
void TaskDisplay(void *pvParameters) {
char buffer_debug[TAILLE_BUFFER_DEBUG];
(void)pvParameters;
int indice_boucle_task_monitor = 0;
int absence_message_gps = 0;
bool memo_gps_stream_arrived_onSerialGPS = true;
bool memo_gps_stream_arrived_onSerialGroveUart1 = true;
TickType_t xLastWakeTime;
const TickType_t xFrequency = 1000;
// Initialise the xLastWakeTime variable with the current time.
xLastWakeTime = xTaskGetTickCount();
TickType_t xDelay1000ms = pdMS_TO_TICKS(1000);
bool SemaphoreFromAcquisitionWasObtained = false;
for (;;) {
#ifdef FONCTIONNEMENT_LIGHT_SLEEP
//attendre le semaphore DisplayToDo
SemaphoreFromAcquisitionWasObtained = false;
if (xSemaphoreTake(xBinarySemaphoreDataToDisplay, pdMS_TO_TICKS(1000)) == pdTRUE) {
SemaphoreFromAcquisitionWasObtained = true;
} else {
//reveil par timeout
//Serial.println("Task display reveil par timeout");
}
#else
vTaskDelayUntil(&xLastWakeTime, xDelay1000ms);
#endif
/*
if (OledMosfetToSwitchOff == true) {
xSemaphoreTake(xMutexSemaphoreBusI2C, portMAX_DELAY);
selectI2Cchannel(INTERNAL_TCA9555_I2C_CHANNEL);
gpioWrite(PIN_TCA9555_33V_OLED, LOW);
OledMosfet = false;
xSemaphoreGive(xMutexSemaphoreBusI2C);
OledMosfetToSwitchOff = false; //job done
}
*/
if (OledMosfet == false) {
// initOledDone = false;
continue;
}
indice_boucle_task_monitor++;
char buffer_debug_local[80];
if (!(indice_boucle_task_monitor % 10)) {
snprintf(buffer_debug_local,sizeof(buffer_debug_local),"OLED Display Task Indice Menu %d\n",indice_menu_demande);
ecrire_debug(buffer_debug_local);
}
//ici on va faire le signalement a l'enregistrement que les données sont pretes , pour une sauvegarde
#ifdef AVEC_SCD41
float local_temperature_scd41 = global_temperature_scd41;
float local_humidity_scd41 = global_humidity_scd41;
float local_C_co2_scd41 = global_C_co2_scd41;
#endif
#define NB_MENUS 2
/*#ifdef FONCTIONNEMENT_LIGHT_SLEEP
indice_menu_demande++;
#endif
*/
indice_menu_demande = indice_menu_demande % NB_MENUS;
if (indice_menu_demande < 0)
indice_menu_demande += NB_MENUS; //pour le rendre positif
if (indice_menu_demande == 0) {
//affichage info gps
if (1) { //gps_stream_arrived_onSerialGroveUart1 == true) {
xSemaphoreTake(xMutexSemaphoreGlobalVariables, portMAX_DELAY);
DateTime DateTimeLocal = DateTimeGlobal;
float dhtHumLocal = dhtHumidityGlobal;
float dhtTempLocal = dhtTemperatureGlobal;
xSemaphoreGive(xMutexSemaphoreGlobalVariables);
unsigned long int current_ms = millis();
int hour = current_ms / 1000 / 3600;
int minute = current_ms / 1000 / 60 - hour * 60;
int seconde = current_ms / 1000 - hour * 3600 - minute * 60;
char buffer_oled1[60];
sprintf(buffer_oled1, "Year : %d/%d/%d", DateTimeLocal.day(), DateTimeLocal.month(), DateTimeLocal.year());
char buffer_oled2[40];
sprintf(buffer_oled2, "RTC : %.2d:%.2d:%.2d #%d", DateTimeLocal.hour(), DateTimeLocal.minute(), DateTimeLocal.second(), 5);
char buffer_oled3[60];
sprintf(buffer_oled3, "Hum : %5.2f", (float)dhtHumLocal);
char buffer_oled4[60];
sprintf(buffer_oled4, "Temp : %5.2f", (float)dhtTempLocal);
//nmeaSerialGroveUart1.getDay(),
//nmeaSerialGroveUart1.getMonth(),
//nmeaSerialGroveUart1.getYear());
display_oled_groove(buffer_oled1, buffer_oled2, buffer_oled3, buffer_oled4, true);
}
}
else
{
//Etat MicroSD
char buffer_oled0[100];
char buffer_oled1[100];
char buffer_oled2[100];
int StateCardrigePin = 0;
if (StateCardrigePin == 0) {
if(cardSizeInMB<4096)
{
sprintf(buffer_oled0, "Taille %5.2f Mo", (float)cardSizeInMB );
sprintf(buffer_oled1, "Libre %5.2fMo", (float)spaceAvailableInMB );
}
else
{
sprintf(buffer_oled0, "Taille %5.2f Go", (float)cardSizeInMB/1024.0f );
sprintf(buffer_oled1, "Libre %5.2f Go", (float)spaceAvailableInMB/1024.0f );
}
sprintf(buffer_oled2, "Open : %d -- Bloc: %d", fileAlreaydyOpen, BlockNumberinFile);
display_oled_groove(buffer_oled0, buffer_oled1, buffer_oled2, "/DATA.TXT", true);
} else {
sprintf(buffer_oled0, "MicroSD absente ");
sprintf(buffer_oled1, "ou Probleme µSD");
display_oled_groove(buffer_oled0, buffer_oled1, NULL, NULL, true);
}
}
}
}
int setupSD()
{
static bool SDbeginAlreayRunned = false;
//ligne tres importante sinon pas possibilité de hotswap!!
if (SDbeginAlreayRunned == true)
SD.end();
if (!SD.begin(chipSelect)) {
Serial.println("initialization failed. Things to check:");
Serial.println("* is a card inserted?");
Serial.println("* is your wiring correct?");
Serial.println("* did you change the chipSelect pin to match your shield or module?");
initSDdone = false;
return -1;
} else {
initSDdone = true;
}
ecrire_debug("SD Card mounted with success\n");
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
ecrire_debug("No SD card attached\n");
SD.end(); //wait for a SD card
initSDdone = false;
return -1;
}
if (cardType == CARD_MMC) {
ecrire_debug("SD Card Type: MMC\n");
} else if (cardType == CARD_SD) {
ecrire_debug("SD Card Type: SDSC\n");
} else if (cardType == CARD_SDHC) {
ecrire_debug("SD Card Type: SDHC\n");
} else {
ecrire_debug("SD Card Type: UNKNOWN\n");
}
uint64_t cardSize = SD.cardSize();
cardSizeInMB = cardSize / (1024 * 1024);
ecrire_debug("Card size: " + String(cardSizeInMB) + " MB\n");
uint64_t bytesAvailable = SD.totalBytes();
spaceAvailableInMB = bytesAvailable / (1024 * 1024);
ecrire_debug("Space available: " + String(spaceAvailableInMB) + " MB\n");
uint64_t spaceUsed = SD.usedBytes();
ecrire_debug("Space used: " + String((int)spaceUsed) + " bytes\n");
SDbeginAlreayRunned = true;
return 0;
}
void openFile()
{
}
void TaskEnregistrement(void *pParameters)
{
File HandleFileEnreg;
int indice_compteur_file = 0;
int FailedOpenCounter = 0;
for (;;)
{
vTaskDelay(100);
if (initSDdone == false)
{
setupSD();
fileAlreaydyOpen = false;
vTaskDelay(500);
}
if (initSDdone == false)
{
vTaskDelay(500);
continue;
}
if (fileAlreaydyOpen == false)
{
//SD.mkdir("/DIRECTORY");
BlockNumberinFile = 0;
HandleFileEnreg = SD.open("/DATA.TXT", FILE_APPEND); //FILE_WRITE + FILE_APPEND);
if (!HandleFileEnreg)
HandleFileEnreg = SD.open("/DATA.TXT", FILE_WRITE);
if (!HandleFileEnreg) {
ecrire_debug(String("Failed to open file ") + String("/DATA.TXT"));
FailedOpenCounter++;
} else {
//HandleFileEnreg.seek(EOF);
fileAlreaydyOpen = true;
FailedOpenCounter = 0;
BlockNumberinFile = 0;
}
}
if (fileAlreaydyOpen == true)
{
char ligne_donnees[100];
int longueur = 0;
longueur += snprintf(ligne_donnees + longueur, sizeof(ligne_donnees) - longueur, "LIGNE %d", BlockNumberinFile);
if (HandleFileEnreg.println(ligne_donnees)) {
//ecrire_debug("File written\n");
HandleFileEnreg.flush();
BlockNumberinFile++;
//ecrire_debug("Flush done\n");
} else {
ecrire_debug("Write failed\n");
vTaskDelay(500);
ecrire_debug("Write failed\n");
vTaskDelay(1000);
HandleFileEnreg.close();
ecrire_debug("File closed\n");
vTaskDelay(1000);
fileAlreaydyOpen = false;
}
}
}
}
//#define WDT_TIMEOUT 1
esp_task_wdt_config_t twdt_config = {
.timeout_ms =25000,// TWDT_TIMEOUT_MS,
.idle_core_mask = (1 << portNUM_PROCESSORS) - 1, // Bitmask of all cores
.trigger_panic = false,
};
void esp32_restart() {
// esp_task_wdt_init(&twdt_config);
esp_task_wdt_add(NULL);
while (true);
}
void taskWDT(void *pParameters)
{
// esp_task_wdt_init(&twdt_config);
esp_task_wdt_add(NULL);
// esp_task_wdt_add(nullptr);
int indice_boucle = 0;
for (;;)
{
vTaskDelay(5000);
esp_task_wdt_reset();
Serial.println("Reset WDT");
// esp32_restart();
}
}
//void task3(void *ptParam)
int indice_boucle = 0;
void taskled()
{
// pinMode(PIN_LED_BLEU, OUTPUT);
// int indice_boucle = 0;
// for (;;)
{
vTaskDelay(500);
if (!((indice_boucle++) % 2))
digitalWrite(PIN_LED_BLEU, LOW);
else
digitalWrite(PIN_LED_BLEU, HIGH);
Serial.println("task 3 ");
}
}
void task2(void *ptParam)
{
pinMode(PIN_LED_ROUGE, OUTPUT);
int indice_boucle = 0;
for (;;)
{
vTaskDelay(1000);
if (!((indice_boucle++) % 2))
digitalWrite(PIN_LED_ROUGE, LOW);
else
digitalWrite(PIN_LED_ROUGE, HIGH);
Serial.println("task 2 ");
}
}
void taskGeneric(void *pvParameters)
{
ParamStruct *ptrparamstruct;
ptrparamstruct = (ParamStruct *)pvParameters;
uint32_t numTask = ptrparamstruct->arg2;
for (;;)
{
vTaskDelay(ptrparamstruct->arg1);
Serial.println("task Generic");//,numTask);
}
}
void task1(void *ptParam)
{
pinMode(PIN_LED_VERTE, OUTPUT);
int indice_boucle = 0;
for (;;)
{
vTaskDelay(250);
if (!((indice_boucle++) % 2))
digitalWrite(PIN_LED_VERTE, LOW);
else
digitalWrite(PIN_LED_VERTE, HIGH);
Serial.println("task 1 ");
}
}
////////////////////RTC DS1307
RTC_DS1307 rtc;
bool rtcInitdone = false;
void setupRTC () {
if (! rtc.begin()) {
ecrire_debug("Couldn't find RTC");
rtcInitdone = false;
return;
}
if (! rtc.isrunning()) {
ecrire_debug("RTC is NOT running, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
rtcInitdone = true;
return;
// When time needs to be re-set on a previously configured device, the
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
void TaskRTC(void *pParameters) {
for (;;)
{
taskled();
if (rtcInitdone == false)
{
xSemaphoreTake(xMutexSemaphoreBusI2C, portMAX_DELAY);
setupRTC();
xSemaphoreGive(xMutexSemaphoreBusI2C);
}
//Delay 5s
vTaskDelay(500);
if (rtcInitdone == false)
continue;
xSemaphoreTake(xMutexSemaphoreBusI2C, portMAX_DELAY);
DateTime time = rtc.now();
xSemaphoreGive(xMutexSemaphoreBusI2C);
xSemaphoreTake(xMutexSemaphoreGlobalVariables, portMAX_DELAY);
DateTimeGlobal = time;
xSemaphoreGive(xMutexSemaphoreGlobalVariables);
//Full Timestamp
/*Serial.println(String("DateTime::TIMESTAMP_FULL:\t") + time.timestamp(DateTime::TIMESTAMP_FULL));
//Date Only
Serial.println(String("DateTime::TIMESTAMP_DATE:\t") + time.timestamp(DateTime::TIMESTAMP_DATE));
//Full Timestamp
Serial.println(String("DateTime::TIMESTAMP_TIME:\t") + time.timestamp(DateTime::TIMESTAMP_TIME));
Serial.println("\n");
*/
}
}
////////////////
unsigned long int LastButtonTouchedMS=0;
void IRAM_ATTR ISR_BUTTON() {
//un bouton a été appuyé , il a généré une interruption
//on memorise le temps ou cela s'est produit
//pour pouvoir gerer cela
LastButtonTouchedMS = millis();
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(interruptSemaphoreBUTTON, &xHigherPriorityTaskWoken);
}
void TaskDetectBUTTON(void *pvParameters) {
for (;;) {
if (xSemaphoreTake(interruptSemaphoreBUTTON, portMAX_DELAY) == pdPASS) {
ecrire_debug("Detected Button\n");
indice_menu_demande++;
vTaskDelay(500);//pour ignorer les rebonds
xQueueReset(interruptSemaphoreBUTTON);
}
}
}
//////////////////////////////
ParamStruct paramstruct1;
ParamStruct paramstruct2;
ParamStruct paramstruct3;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("STARTUP ESP32");
vTaskDelay(2000);
//creation des MUTEX liées a des I/O etc
xMutexSemaphoreBusI2C = xSemaphoreCreateMutex();
xMutexSemaphoreRTC = xSemaphoreCreateMutex();
xMutexSemaphoreDateTimeRTC = xSemaphoreCreateMutex();
xMutexSemaphoreForMeasurementSHT30 = xSemaphoreCreateMutex();
xMutexSemaphoreSDAccess = xSemaphoreCreateMutex();
xMutexSemaphoreDebug = xSemaphoreCreateMutex();
xMutexSemaphoreBusSPI = xSemaphoreCreateMutex();
xMutexSemaphoreGlobalVariables = xSemaphoreCreateMutex();
interruptSemaphoreBUTTON = xSemaphoreCreateBinary();
paramstruct1.arg1 = 100;
paramstruct1.arg2 = 1;
paramstruct2 = paramstruct1;
paramstruct2.arg1 = 500;
paramstruct3 = paramstruct1;
paramstruct3.arg1 = 1000;
xTaskCreatePinnedToCore(taskWDT, "WDT", 1024, NULL, 3, NULL, CORE_ONE);
xTaskCreatePinnedToCore(TaskEnregistrement, "Enregistrement", 8192, ¶mstruct3, 3, NULL, CORE_ONE);
xTaskCreatePinnedToCore(TaskDisplay, "OLED", 8192, ¶mstruct3, 3, NULL, CORE_ONE);
xTaskCreatePinnedToCore(TaskRTC, "RTC", 8192, ¶mstruct3, 3, NULL, 0);
xTaskCreatePinnedToCore(TaskDHT, "DHT", 1024, ¶mstruct3, 3, NULL, 0);
//interruption pour les boutons
pinMode(12, INPUT_PULLUP);
if (interruptSemaphoreBUTTON != NULL) {
attachInterrupt(digitalPinToInterrupt(12), ISR_BUTTON, FALLING);
}
xTaskCreatePinnedToCore(TaskDetectBUTTON, "BTN", 1024, ¶mstruct3, 3, NULL, 0);
}
void loop() {
//suppression de cette tache qui ne sert a rien dans notre cas
vTaskDelete(NULL);
}