misionSolar

Misión Solar

sistema didáctico para conocer el sistema solar


// codigo para nave espacial modular
/* NAVE:   _
          /_\  PUNTA
          |_|  MODULO 1
          |_|  MODULO 2
          |O|  CAPSULA
          |_|  MODULO 3
          |_|  MODULO 4
         |___| PROPULSOR
*/

// BIBLIOTECAS INCLUIDAS
#include <SD.h>
#include <SPI.h>
#include <FS.h>
#include <SPIFFS.h>
#include <TFT_eSPI.h>
#include <AnimatedGIF.h>

// --PINES DE MODULOS--
// MODULO 1 (UP LVL2)
int pinesMod1[3] = { 13, 12, 14 };
// MODULO 2 (UP LVL1)
int pinesMod2[3] = { 27, 26, 25 };
// MODULO 3 (DOWN LVL1)
int pinesMod3[3] = { 34, 21, 22 };
// MODULO 4 (DOWN LVL2)
int pinesMod4[3] = { 33, 32, 35 };

// PANTALLA
TFT_eSPI tft = TFT_eSPI();
// LECTOR SD
#define SD_CS_PIN 5

//gifs
AnimatedGIF gif;
File gifFile;
const char *filenameIntro = "/logo.GIF";
const char *filenameLogoOUT = "/logoOUT.GIF";
const char *filenameWait = "/prueba.GIF";
const char *filenameReady = "/prueba2.GIF";


void setup() {

  // iniciar SD
  if (!SD.begin()) {
    Serial.println("Card Mount Failed");
    return;
  }

  // configurar pines modulos
  pinMode(pinesMod1[0], INPUT);
  pinMode(pinesMod1[1], INPUT);
  pinMode(pinesMod1[2], INPUT);

  pinMode(pinesMod2[0], INPUT);
  pinMode(pinesMod2[1], INPUT);
  pinMode(pinesMod2[2], INPUT);

  pinMode(pinesMod3[0], INPUT);
  pinMode(pinesMod3[1], INPUT);
  pinMode(pinesMod3[2], INPUT);

  pinMode(pinesMod4[0], INPUT);
  pinMode(pinesMod4[1], INPUT);
  pinMode(pinesMod4[3], INPUT);

  // inicio serial
  Serial.begin(115200);

  //inicio pantalla
  tft.begin();
  tft.setRotation(2);  // Adjust Rotation of your screen (0-3)
  tft.fillScreen(TFT_BLACK);

  // Initialize SPIFFS
  Serial.println("Initialize SPIFFS...");
  if (!SPIFFS.begin(true)) {
    Serial.println("SPIFFS initialization failed!");
  }

  Serial.println("Formatting SPIFFS...");
  SPIFFS.format();  // This will erase all the files, change as needed, SPIFFs is non-volatile memory
  Serial.println("SPIFFS formatted successfully.");

  // Open GIF file from SD card
  Serial.println("Openning GIF file from SD card...");

  ///////////// DEBO TRANSFORMAR ESTO EN UNA FUNCION
  // GIF INTRO
  File sdFileIntro = SD.open(filenameIntro);
  File spiffsFileIntro = SPIFFS.open(filenameIntro, FILE_WRITE, true);
  Serial.println("Copy GIF in SPIFFS...");
  byte bufferA[512];
  while (sdFileIntro.available()) {
    int bytesReadA = sdFileIntro.read(bufferA, sizeof(bufferA));
    spiffsFileIntro.write(bufferA, bytesReadA);
  }
  spiffsFileIntro.close();
  sdFileIntro.close();

  // GIF LOGO OUT
  File sdFileLogoOUT = SD.open(filenameLogoOUT);
  File spiffsFileLogoOUT = SPIFFS.open(filenameLogoOUT, FILE_WRITE, true);
  Serial.println("Copy GIF in SPIFFS...");
  byte bufferlogoOUT[512];
  while (sdFileLogoOUT.available()) {
    int bytesReadLogoOUT = sdFileLogoOUT.read(bufferlogoOUT, sizeof(bufferlogoOUT));
    spiffsFileLogoOUT.write(bufferlogoOUT, bytesReadLogoOUT);
  }
  spiffsFileLogoOUT.close();
  sdFileLogoOUT.close();

  // GIF WAIT
  File sdFileWait = SD.open(filenameWait);
  File spiffsFileWait = SPIFFS.open(filenameWait, FILE_WRITE, true);
  Serial.println("Copy GIF in SPIFFS...");
  byte bufferB[512];
  while (sdFileWait.available()) {
    int bytesReadB = sdFileWait.read(bufferB, sizeof(bufferB));
    spiffsFileWait.write(bufferB, bytesReadB);
  }
  spiffsFileWait.close();
  sdFileWait.close();

  // GIF READY
  File sdFileReady = SD.open(filenameReady);
  File spiffsFileReady = SPIFFS.open(filenameReady, FILE_WRITE, true);
  Serial.println("Copy GIF in SPIFFS...");
  byte bufferC[512];
  while (sdFileReady.available()) {
    int bytesReadC = sdFileReady.read(bufferC, sizeof(bufferC));
    spiffsFileReady.write(bufferC, bytesReadC);
  }
  spiffsFileReady.close();
  sdFileReady.close();

  // Initialize the GIF
  Serial.println(millis());
  gif.begin(BIG_ENDIAN_PIXELS);
}

int sumaModulosAntes = -1;

void loop() {

  // mostrar logo por 2 segundos
  while (millis() < 20000) {
    if (gif.open(filenameIntro, fileOpen, fileClose, fileRead, fileSeek, GIFDraw)) {
      tft.startWrite();
      while (gif.playFrame(true, NULL)) {
      }
      gif.close();
      tft.endWrite();
    }
  }
  // mostrar animacion de encendido de la nave
  if (gif.open(filenameLogoOUT, fileOpen, fileClose, fileRead, fileSeek, GIFDraw)) {
    tft.startWrite();
    while (gif.playFrame(true, NULL)) {
    }
    gif.close();
    tft.endWrite();
  }
  unsigned long timeInit = millis();
  while (true) {
    unsigned long timeNow = millis() - timeInit;

    if (cualModulo(1) + cualModulo(2) + cualModulo(3) + cualModulo(4) == 0 && sumaModulosAntes != 0) {
      // animacion de espera
      tft.fillScreen(TFT_BLACK);
      tft.setCursor(10, 100, 2);
      tft.setTextColor(TFT_WHITE);
      tft.setTextSize(2);
      tft.println("ensambla la nave");
      tft.setCursor(32, 130, 2);
      tft.println("para tu mision");
      /*if (gif.open(filenameWait, fileOpen, fileClose, fileRead, fileSeek, GIFDraw)) {
        tft.startWrite();
        while (gif.playFrame(true, NULL)) {
        }
        gif.close();
        tft.endWrite();
      }*/
    } else {
      // muestra el codigo de configuracion de la nave porla pantalla
      // luego animacion de nave lista
      if (cualModulo(1) + cualModulo(2) + cualModulo(3) + cualModulo(4) != sumaModulosAntes) {

        tft.fillScreen(TFT_BLACK);
        tft.setCursor(30, 110, 2);
        tft.setTextColor(TFT_WHITE);
        tft.setTextSize(2);

        /*
      // codigo de prueba
      if (cualModulo(2) != 0){
        String texto;
        switch (cualModulo(2)) {
        case 1:
        texto = "Gravedad";
        break;
        case 2:
        texto = "Energia";
        break;
        case 3:
        texto = "Calor";
        break;
        case 4:
        texto = "Frio";
        break;
        case 5:
        break;
        case 6:
        break;
        case 7:
        texto = "Sonda";
        break;
        }
        tft.println(texto);
      }*/

        int moduloActivo[4];
        int modulosEscogidos[4];

        for (int i = 0; i < 4; i++) {
          int numeroMod = cualModulo(i + 1);
          if (numeroMod == 7) {
            modulosEscogidos[i] = 4;
          } else {
            modulosEscogidos[i] = numeroMod - 1;
          }
          if (numeroMod == 0) {
            moduloActivo[i] = 0;
            modulosEscogidos[i] = random(0, 9);
          } else {
            moduloActivo[i] = random(1, 9);
          }
        }

        tft.println(String(random(0, 9)) + String(moduloActivo[0]) + String(modulosEscogidos[0]) + String(moduloActivo[1]) + String(modulosEscogidos[1]) + String(random(0, 9)) + String(moduloActivo[2]) + String(modulosEscogidos[2]) + String(moduloActivo[3]) + String(modulosEscogidos[3]) + String(random(0, 9)));
        
      }

      /*if (gif.open(filenameReady, fileOpen, fileClose, fileRead, fileSeek, GIFDraw)) {
        tft.startWrite();
        while (gif.playFrame(true, NULL)) {
        }
        gif.close();
        tft.endWrite();
      }*/
    }
    sumaModulosAntes = cualModulo(1) + cualModulo(2) + cualModulo(3) + cualModulo(4);
    Serial.println(sumaModulosAntes);
  }
}


// funcion para identificar el modulo conectado
// transformando de binario (3 bits) a un numero entre 0 y 7
int cualModulo(int mod) {
  int n = 0;
  if (mod == 1) {
    if (digitalRead(pinesMod1[0])) n += 4;
    if (digitalRead(pinesMod1[1])) n += 2;
    if (digitalRead(pinesMod1[2])) n += 1;
  }
  if (mod == 2) {
    if (digitalRead(pinesMod2[0])) n += 4;
    if (digitalRead(pinesMod2[1])) n += 2;
    if (digitalRead(pinesMod2[2])) n += 1;
  }
  if (mod == 3) {
    if (digitalRead(pinesMod3[0])) n += 4;
    if (digitalRead(pinesMod3[1])) n += 2;
    if (digitalRead(pinesMod3[2])) n += 1;
  }
  if (mod == 4) {
    if (digitalRead(pinesMod4[0])) n += 4;
    if (digitalRead(pinesMod4[1])) n += 2;
    if (digitalRead(pinesMod4[2])) n += 1;
  }
  return n;
}

///////// FUNCIONES DE LOS GIF //////////

void *fileOpen(const char *filename, int32_t *pFileSize) {
  gifFile = SPIFFS.open(filename, FILE_READ);
  *pFileSize = gifFile.size();
  if (!gifFile) {
    Serial.println("Failed to open GIF file from SPIFFS!");
  }
  return &gifFile;
}

void fileClose(void *pHandle) {
  gifFile.close();
}

int32_t fileRead(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen) {
  int32_t iBytesRead;
  iBytesRead = iLen;
  if ((pFile->iSize - pFile->iPos) < iLen)
    iBytesRead = pFile->iSize - pFile->iPos;
  if (iBytesRead <= 0)
    return 0;

  gifFile.seek(pFile->iPos);
  int32_t bytesRead = gifFile.read(pBuf, iLen);
  pFile->iPos += iBytesRead;

  return bytesRead;
}

int32_t fileSeek(GIFFILE *pFile, int32_t iPosition) {
  if (iPosition < 0)
    iPosition = 0;
  else if (iPosition >= pFile->iSize)
    iPosition = pFile->iSize - 1;
  pFile->iPos = iPosition;
  gifFile.seek(pFile->iPos);
  return iPosition;
}

/////////////////////////////////////////

// GIFDraw is called by AnimatedGIF library frame to screen

#define DISPLAY_WIDTH  tft.width()
#define DISPLAY_HEIGHT tft.height()
#define BUFFER_SIZE 256            // Optimum is >= GIF width or integral division of width

#ifdef USE_DMA
  uint16_t usTemp[2][BUFFER_SIZE]; // Global to support DMA use
#else
  uint16_t usTemp[1][BUFFER_SIZE];    // Global to support DMA use
#endif
bool     dmaBuf = 0;
  
// Draw a line of image directly on the LCD
void GIFDraw(GIFDRAW *pDraw)
{
  uint8_t *s;
  uint16_t *d, *usPalette;
  int x, y, iWidth, iCount;

  // Displ;ay bounds chech and cropping
  iWidth = pDraw->iWidth;
  if (iWidth + pDraw->iX > DISPLAY_WIDTH)
    iWidth = DISPLAY_WIDTH - pDraw->iX;
  usPalette = pDraw->pPalette;
  y = pDraw->iY + pDraw->y; // current line
  if (y >= DISPLAY_HEIGHT || pDraw->iX >= DISPLAY_WIDTH || iWidth < 1)
    return;

  // Old image disposal
  s = pDraw->pPixels;
  if (pDraw->ucDisposalMethod == 2) // restore to background color
  {
    for (x = 0; x < iWidth; x++)
    {
      if (s[x] == pDraw->ucTransparent)
        s[x] = pDraw->ucBackground;
    }
    pDraw->ucHasTransparency = 0;
  }

  // Apply the new pixels to the main image
  if (pDraw->ucHasTransparency) // if transparency used
  {
    uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent;
    pEnd = s + iWidth;
    x = 0;
    iCount = 0; // count non-transparent pixels
    while (x < iWidth)
    {
      c = ucTransparent - 1;
      d = &usTemp[0][0];
      while (c != ucTransparent && s < pEnd && iCount < BUFFER_SIZE )
      {
        c = *s++;
        if (c == ucTransparent) // done, stop
        {
          s--; // back up to treat it like transparent
        }
        else // opaque
        {
          *d++ = usPalette[c];
          iCount++;
        }
      } // while looking for opaque pixels
      if (iCount) // any opaque pixels?
      {
        // DMA would degrtade performance here due to short line segments
        tft.setAddrWindow(pDraw->iX + x, y, iCount, 1);
        tft.pushPixels(usTemp, iCount);
        x += iCount;
        iCount = 0;
      }
      // no, look for a run of transparent pixels
      c = ucTransparent;
      while (c == ucTransparent && s < pEnd)
      {
        c = *s++;
        if (c == ucTransparent)
          x++;
        else
          s--;
      }
    }
  }
  else
  {
    s = pDraw->pPixels;

    // Unroll the first pass to boost DMA performance
    // Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
    if (iWidth <= BUFFER_SIZE)
      for (iCount = 0; iCount < iWidth; iCount++) usTemp[dmaBuf][iCount] = usPalette[*s++];
    else
      for (iCount = 0; iCount < BUFFER_SIZE; iCount++) usTemp[dmaBuf][iCount] = usPalette[*s++];

#ifdef USE_DMA // 71.6 fps (ST7796 84.5 fps)
    tft.dmaWait();
    tft.setAddrWindow(pDraw->iX, y, iWidth, 1);
    tft.pushPixelsDMA(&usTemp[dmaBuf][0], iCount);
    dmaBuf = !dmaBuf;
#else // 57.0 fps
    tft.setAddrWindow(pDraw->iX, y, iWidth, 1);
    tft.pushPixels(&usTemp[0][0], iCount);
#endif

    iWidth -= iCount;
    // Loop if pixel buffer smaller than width
    while (iWidth > 0)
    {
      // Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
      if (iWidth <= BUFFER_SIZE)
        for (iCount = 0; iCount < iWidth; iCount++) usTemp[dmaBuf][iCount] = usPalette[*s++];
      else
        for (iCount = 0; iCount < BUFFER_SIZE; iCount++) usTemp[dmaBuf][iCount] = usPalette[*s++];

#ifdef USE_DMA
      tft.dmaWait();
      tft.pushPixelsDMA(&usTemp[dmaBuf][0], iCount);
      dmaBuf = !dmaBuf;
#else
      tft.pushPixels(&usTemp[0][0], iCount);
#endif
      iWidth -= iCount;
    }
  }
} /* GIFDraw() */