Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request #39

Open
dallen98 opened this issue Sep 18, 2022 · 2 comments
Open

Feature Request #39

dallen98 opened this issue Sep 18, 2022 · 2 comments

Comments

@dallen98
Copy link

dallen98 commented Sep 18, 2022

Using Arduino ide 1.8.19, Teensyduino 1.57, Teensy4.1 board, windows11
I have inserted the below code onto lines 1,2,7,103,106,107,200 plus a delay on line 201 into my sketch further below that drives leds in the hope of bringing the mtp window up for a few minutes giving me time to upload my png images before then proceeding to run my led code starting on line 202 in the loop without any success, any suggestions or perhaps a "run mtp once then do other stuff afterwards" example sketch for your mtp library thanks
ps I have Tycommander installed which through its reset allows me to invoke the above

#include <SD.h>
#include <MTP_Teensy.h>

#define CS_SD BUILTIN_SDCARD  // Works on T_3.6 and T_4.1
//#define CS_SD 10  // Works on SPI with this CS pin
void setup()
{
  // mandatory to begin the MTP session.
  MTP.begin();

  // Add SD Card
  SD.begin(CS_SD);
  MTP.addFilesystem(SD, "SD Card");
}

void loop() {
  MTP.loop();  //This is mandatory to be placed in the loop code.
}

My LED Code...

#include <SD.h>
#include <MTP_Teensy.h>
#include <TDWS28XX.h>
#include <SdFat.h> 
#include <PNGdec.h> 
using namespace TDWS28XX;
#define CS_SD BUILTIN_SDCARD
const uint8_t NumberOfChannels = 1; 
const uint16_t NumberOfPixelsPerChannel = 256; 
const uint16_t NumberOfPixelsPerRow = 16;

const uint8_t FramesPerSecond = 26; 
const uint8_t BrightnessPercent = 8; 


const uint16_t NumberOfRows = NumberOfPixelsPerChannel / NumberOfPixelsPerRow * NumberOfChannels * 2;
const unsigned long FrameIntervalMs = 1000 / FramesPerSecond;
DMAMEM PixelBuffer<NumberOfPixelsPerChannel, TRICOLOR, DOUBLE_BUFFER> pbeven;
DMAMEM PixelBuffer<NumberOfPixelsPerChannel, TRICOLOR, DOUBLE_BUFFER> pbodd;
PixelDriver pdeven(pbeven);
PixelDriver pdodd(pbodd);
PNG png;
SdFs sdfs;
FsFile rootDir;
FsFile cacheDir;
extern const uint8_t gamma8[];
unsigned long lastFrameStartMs;
unsigned frameNumber;
unsigned numberOfFrames;
bool bufferLoaded;

struct ImagePosition {
  uint16_t x;
  uint16_t y;
};

struct DisplayPosition {
  PixelDriver &d;
  uint16_t x;
  uint16_t y;
};

// translate logical pixel position in the PNG to physical display position
inline DisplayPosition convert(const ImagePosition &logical) {
  uint16_t x, y;
  y = logical.y / (NumberOfPixelsPerChannel / NumberOfPixelsPerRow);
  uint16_t a = logical.y % (NumberOfPixelsPerChannel / NumberOfPixelsPerRow);
  x = (a & 1)
    ? a * NumberOfPixelsPerRow + (NumberOfPixelsPerRow - 1 - logical.x)
    : a * NumberOfPixelsPerRow + logical.x;
  if (y & 1) {
    return { pdodd, x, static_cast<uint16_t>(y/2) };
  } else {
    return { pdeven, x, static_cast<uint16_t>(y/2) };
  }
}

void* pngOpen(const char *filename, int32_t *size) {
  static FsFile f;
  if ((f = sdfs.open(filename))) {
    *size = f.size();
    return &f;
  } else {
    return 0;
  }
}

void pngClose(void *file) {
  FsFile *f = static_cast<FsFile *>(file);
  f->close();
}

int32_t pngRead(PNGFILE *handle, uint8_t *buffer, int32_t length) {
  FsFile *f = static_cast<FsFile *>(handle->fHandle);
  return f->read(buffer, length);
}

int32_t pngSeek(PNGFILE *handle, int32_t position) {
  FsFile *f = static_cast<FsFile *>(handle->fHandle);
  return f->seek(position);
}

inline uint8_t dim(uint8_t v) {
  return v * BrightnessPercent / 100;
}

void pngDraw(PNGDRAW *pDraw) {
  uint8_t* b = pDraw->pPixels;
  uint16_t y = static_cast<uint16_t>(pDraw->y);
  Color c;
  for (uint16_t x = 0; x < NumberOfPixelsPerRow; ++x) {
    DisplayPosition p = convert(ImagePosition{x, y});
    c.GRB.red = dim(gamma8[*b++]);
    c.GRB.green = dim(gamma8[*b++]);
    c.GRB.blue = dim(gamma8[*b++]);
    p.d.setPixel(p.y, p.x, c);
  }
}

void setup() {
  Serial.begin(1000000);
    // mandatory to begin the MTP session.
  MTP.begin();

  // Add SD Card
  SD.begin(CS_SD);
  MTP.addFilesystem(SD, "SD Card");
  Serial.print("display ");
  Serial.print(NumberOfPixelsPerRow);
  Serial.print("x");
  Serial.println(NumberOfRows);

#ifdef ARNCONFIG
  if (! pdeven.begin(FLEXIO1, { 2, 3, 4 }) || ! pdodd.begin(FLEXIO2, { 7, 8, 9 })) {
#else
  if (! pdeven.begin(FLEXIO1, { 2, 3, 4 }) | ! pdodd.begin(FLEXIO2, { 10,11,12 })) {
#endif
    Serial.println("configuration error");
    for (;;);
  }

  for (uint8_t i = 0; i < NumberOfChannels; ++i) {
    pdeven.setChannelType(i, GRB);
    pdodd.setChannelType(i, GRB);
  }
  
#ifdef ARNCONFIG
  if (! sdfs.begin(SdSpiConfig(10, DEDICATED_SPI, SD_SCK_MHZ(20)))) {
#else
  if (! sdfs.begin(SdioConfig(FIFO_SDIO))) {
#endif
    Serial.println("unable to access SD card");
    for (;;);
  }
  
  if (! rootDir.open("/")
      || (cacheDir.mkdir(&rootDir, "cache"), ! cacheDir.open("/cache"))) {
    Serial.println("unable to open directory");
    for (;;);
  }

  Serial.println("caching PNGs...");
  char fn[9];
  while (sprintf(fn, "%04u.png", frameNumber), rootDir.exists(fn)) {
    int rc = png.open(fn, pngOpen, pngClose, pngRead, pngSeek, pngDraw);
    if (rc == PNG_SUCCESS) {
      Serial.print("opened ");
      Serial.println(fn);
    } else {
      Serial.println("error PNG open");
      break;
    }
    if (png.getWidth() != NumberOfPixelsPerRow
        || png.getHeight() != NumberOfRows
        || png.getPixelType() != PNG_PIXEL_TRUECOLOR) {
      png.close();
      Serial.println("error PNG format");
      break;
    }

    // looks like a valid PNG
    rc = png.decode(nullptr, 0);
    png.close();
    if (rc != PNG_SUCCESS) {
      Serial.println("error PNG decode");
      break;
    }

    // write cache file
    FsFile f;
    strcpy(fn + 5, "bin");
    if (! f.open(&cacheDir, fn, O_WRITE | O_CREAT | O_TRUNC)) {
      Serial.println("error cache open");
      break;
    }
    if (! f.preAllocate(pdodd.getBufferSize() * 2)) {
      Serial.println("error preallocation");
      break;
    }
    if (f.write(const_cast<const uint8_t*>(pdeven.getActiveBufferPtr()), pdeven.getBufferSize()) != pdeven.getBufferSize()
        || f.write(const_cast<const uint8_t*>(pdodd.getActiveBufferPtr()), pdodd.getBufferSize()) != pdodd.getBufferSize()) {
      Serial.println("error cache write");
      f.close();
      if (! f.remove(fn)) {
        Serial.println("error remove cache");
      }
      break;
    }
    f.close();
    ++frameNumber;
  }
  numberOfFrames = frameNumber;
  Serial.println("...done.");
  
  frameNumber = 0;
}


void loop() {
  MTP.loop();
  delay(20000);
  unsigned long nowMs = millis();

  if (bufferLoaded) {
    if (nowMs - lastFrameStartMs > FrameIntervalMs) {
      if (pdeven.bufferReady() && pdodd.bufferReady()) {
        pdeven.flipBuffers();
        pdodd.flipBuffers();
        Serial.print(1000 / (nowMs - lastFrameStartMs));
        Serial.println("fps");
        lastFrameStartMs = nowMs;
        bufferLoaded = false;
      }
    }
  } else {
    unsigned long a, b;
    FsFile f;
    char fn[9];
    if (frameNumber < numberOfFrames) {
      a = micros();
      sprintf(fn, "%04u.bin", frameNumber);
      if (f.open(&cacheDir, fn, O_READ)) {
        Serial.print("opened ");
        Serial.println(fn);
        if (f.read(const_cast<uint8_t*>(pdeven.getInactiveBufferPtr()), pdeven.getBufferSize()) == static_cast<int>(pdeven.getBufferSize())
            && f.read(const_cast<uint8_t*>(pdodd.getInactiveBufferPtr()), pdodd.getBufferSize()) == static_cast<int>(pdodd.getBufferSize())) {
          bufferLoaded = true;
        } else {
          Serial.println("error reading display buffer");
        }
        f.close();
      } else {
        Serial.print("error opening ");
        Serial.println(fn);
      }
      ++frameNumber;
      b = micros();
      Serial.print("us ");
      Serial.println(b - a);
    } else {
      frameNumber = 0;
    }
  }

  //Serial.print("do other useful stuff here ");
}

// gamma8 from: https://learn.adafruit.com/led-tricks-gamma-correction/the-quick-fix
//
const uint8_t gamma8[] = {
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,
    1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,
    2,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  5,  5,  5,
    5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  9,  9,  9, 10,
   10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
   17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
   25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
   37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
   51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
   69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
   90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
  115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
  144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
  177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
  215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255
};
@Fluxanode
Copy link

This is a good idea! Any update? Has it been implemented?

@KurtE
Copy link
Owner

KurtE commented Mar 26, 2023

Sorry, I did not notice this issue earlier. Hope you don't mind I edited your comments to put in code tags to make it easier to follow.

Are you still having an issue?

Feature request?
In loop:

void loop() {
  MTP.loop();
  delay(20000);

needless to say each call into loop in addition to the time taken in MTP.loop, it will have at least a 20 second delay before anything else happens.

If you are in a time sensitive area of code, you control when MTP.loop() is called. I have not played with it enough to know what happens if you don't call it for many seconds. The host may simply time you out and drop the connection.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants