Forum: Mikrocontroller und Digitale Elektronik Könnte mir jemand diesen C++ Code in eine class Bibliothek umschreiben


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Martin M. (ats3788)


Lesenswert?

Hallo
Ich versuchte heute morgen diese Funktionen in eine Object Class 
umzuschreiben.
War so weit kein Problem nur in
int16_t rc = _png.open(PngName.c_str(), pngOpen, pngClose, pngRead, 
pngSeek, pngDraw); hat der Compiler ein Problem die Callbacks zu 
compilen.
Meine C++ Fähigkeiten sind auf "C" beschränkt.
1
mein Header
2
#ifndef __MYPNGDEC__
3
#define __MYPNGDEC__
4
5
6
#include <Arduino.h>
7
#include "FS.h"
8
#include "SD.h"
9
#include "SPI.h"
10
#include <TFT_eSPI.h>     
11
#include <pngdec.h>
12
13
#define MAX_IMAGE_WIDTH 320 // Adjust for your images
14
15
16
17
18
class PngClass {
19
public:
20
void InitPngLib(TFT_eSPI tft );
21
void listDir(fs::FS &fs, const char * dirname, uint8_t levels);
22
void DrawPng(int x, int y,const String PngName);
23
24
private:
25
TFT_eSPI * _tft;
26
File pngfile;
27
PNG _png;
28
int xpos;
29
int ypos;
30
void * pngOpen(const char *filename, int32_t *size);
31
void    pngClose(void *handle);
32
int32_t pngRead(PNGFILE *page, uint8_t *buffer, int32_t length);
33
int32_t pngSeek(PNGFILE *page, int32_t position);
34
String readFile(fs::FS &fs, const char * path);  
35
void pngDraw(PNGDRAW *pDraw);
36
};
37
38
#endif
39
40
mein C++ File 
41
#include "MyPngLib.h"
42
43
void PngClass::InitPngLib(TFT_eSPI tft )
44
{
45
_tft = tft;
46
 //SPIClass spi = SPIClass(VSPI);
47
48
  Serial.println("**********************************************************");  
49
  Serial.print("MOSI: ");
50
  Serial.println(MOSI);
51
  Serial.print("MISO: ");
52
  Serial.println(MISO);
53
  Serial.print("SCK: ");
54
  Serial.println(SCK);
55
  Serial.print("SS: ");
56
  Serial.println(SS);  
57
  Serial.println("**********************************************************");  
58
    
59
 //if (!SD.begin(SS, spi, 80000000)) 
60
 if (!SD.begin(SS)) 
61
 {
62
      Serial.println("initialization failed!");
63
    }
64
65
  Serial.println("initialization done.");
66
  listDir(SD, "/", 0);
67
68
}
69
70
71
72
void PngClass::listDir(fs::FS &fs, const char * dirname, uint8_t levels) 
73
{
74
  Serial.printf("Listing directory: %s\n", dirname);
75
76
  File root = fs.open(dirname);
77
  if (!root) {
78
    Serial.println("Failed to open directory");
79
    return;
80
  }
81
  if (!root.isDirectory()) {
82
    Serial.println("Not a directory");
83
    return;
84
  }
85
86
  File file = root.openNextFile();
87
  while (file) {
88
    if (file.isDirectory()) {
89
      Serial.print("  DIR : ");
90
      Serial.println(file.name());
91
      if (levels) {
92
        listDir(fs, file.path(), levels - 1);
93
      }
94
    } else {
95
      Serial.print("  FILE: ");
96
      Serial.print(file.name());
97
      Serial.print("  SIZE: ");
98
      Serial.println(file.size());
99
    }
100
    file = root.openNextFile();
101
  }
102
}
103
104
105
void * PngClass::pngOpen(const char *filename, int32_t *size) 
106
{
107
  Serial.printf("Attempting to open %s\n", filename);
108
  File _pngfile = SD.open(filename, "r");
109
  *size = _pngfile.size();
110
  return &pngfile;
111
}
112
113
void PngClass::pngClose(void *handle)
114
 {
115
  File _pngfile = *((File*)handle);
116
  if (_pngfile) _pngfile.close();
117
}
118
119
int32_t PngClass::pngRead(PNGFILE *page, uint8_t *buffer, int32_t length) 
120
{
121
  if (!pngfile) return 0;
122
  page = page; // Avoid warning
123
  return pngfile.read(buffer, length);
124
}
125
126
int32_t PngClass::pngSeek(PNGFILE *page, int32_t position)
127
 {
128
  if (!pngfile) return 0;
129
  page = page; // Avoid warning
130
  return pngfile.seek(position);
131
}
132
133
//=========================================v==========================================
134
//                                      _pngDraw
135
//====================================================================================
136
// This next function will be called during decoding of the _png file to
137
// render each image line to the _tft.  If you use a different _tft library
138
// you will need to adapt this function to suit.
139
// Callback function to draw pixels to the display
140
void PngClass::pngDraw(PNGDRAW *pDraw)
141
 {
142
  uint16_t lineBuffer[MAX_IMAGE_WIDTH];
143
  static uint16_t dmaBuffer[MAX_IMAGE_WIDTH]; // static so buffer persists after fn exit
144
  _png.getLineAsRGB565(pDraw, lineBuffer, PNG_RGB565_BIG_ENDIAN, 0xffffffff);
145
  _tft->pushImageDMA(xpos, ypos + pDraw->y, pDraw->iWidth, 1, lineBuffer, dmaBuffer);
146
}
147
148
149
void PngClass::DrawPng(int x, int y,const String PngName)
150
{
151
      xpos = x;
152
      ypos = y;
153
154
      int16_t rc = _png.open(PngName.c_str(), pngOpen, pngClose, pngRead, pngSeek, pngDraw);
155
      if (rc == PNG_SUCCESS) {
156
        _tft->startWrite();
157
        Serial.printf("image specs: (%d x %d), %d bpp, pixel type: %d\n", _png.getWidth(), _png.getHeight(), _png.getBpp(), _png.getPixelType());
158
        uint32_t dt = millis();
159
        if (_png.getWidth() > MAX_IMAGE_WIDTH) {
160
          Serial.println("Image too wide for allocated lin buffer!");
161
        }
162
        else {
163
          rc = _png.decode(NULL, 0);
164
          _png.close();
165
        }
166
        _tft->endWrite();
167
        // How long did rendering take...
168
        Serial.print(millis()-dt); Serial.println("ms");
169
      }
170
    }
171
172
173
174
175
String PngClass::readFile(fs::FS &fs, const char * path)
176
{
177
  Serial.printf("Reading file: %s\r\n", path);
178
  File file = fs.open(path, "r");
179
  if(!file || file.isDirectory()){
180
    Serial.println("- empty file or failed to open file");
181
    return String();
182
  }
183
  Serial.println("- read from file:");
184
  String fileContent;
185
  while(file.available()){
186
    fileContent+=String((char)file.read());
187
  }
188
  Serial.println(fileContent);
189
  return fileContent;
190
}


Wo ist der Artikel Code zu formatieren.

[Mod: nimm die [c] Tags wie in der Anleitung beschrieben]

: Bearbeitet durch Moderator
von Oliver S. (oliverso)


Lesenswert?

Martin M. schrieb:
> Wo ist der Artikel Code zu formatieren.

Das kann dir egal eigentlich sein. Längeren Code immer als Anhang 
anhängen.

Oliver

Beitrag #7769466 wurde vom Autor gelöscht.
von Walter T. (nicolas)


Lesenswert?

Ich hoffe, Dein Arduino hat genug Speicher für ein ganzes entpacktes 
Bild.

von Michael B. (laberkopp)


Lesenswert?

Martin M. schrieb:
> void * PngClass::pngOpen
> File _pngfile = SD.open(filename, "r");
>   return &pngfile;

Ernsthaft ?

Martin M. schrieb:
> pngClose(void *handle)
> File _pngfile = *((File*)handle);
>   if (_pngfile) _pngfile.close();

Martin M. schrieb:
> Meine C++ Fähigkeiten sind auf "C" beschränkt.

von Peter D. (peda)


Lesenswert?

Martin M. schrieb:
> Meine C++ Fähigkeiten sind auf "C" beschränkt.

Man darf ruhig C und C++ zusammen in einer Applikation verwenden. Jeder 
C++ Compiler versteht auch plain C.

Ich kriege von C++ auch immer ganz schnell einen Knoten im Kopf.

von Wastl (hartundweichware)


Lesenswert?

Martin M. schrieb:
> Wo ist der Artikel Code zu formatieren.

Seit mehr als 12 Jahren hier angemeldet und unfähig die Hinweise
zum Posten von Sourcecode zu lesen und zu verstehen.

"Längerer Sourcecode" ist es wenn mehr als eine Bildschirmseite
beansprucht wird.

von Peter D. (peda)


Lesenswert?

Soll sich jemand den Quellcode anschauen, pakt man vorzugsweise das 
komplette Projekt mit allen speziellen Includes und Libs in ein Zip.
Nur so kann jemand prüfen, ob es auch compiliert und linkt.
Niemand ist ein perfekter Programmierer, der aus dem Hut syntaktisch und 
logisch fehlerfreien Code schreiben kann.

von Jens K. (jensky)


Lesenswert?

Walter T. schrieb:
> Ich hoffe, Dein Arduino hat genug Speicher für ein ganzes
> entpacktes
> Bild.

ja, hat er! Siehe:
Beitrag "Frage an die STM32-Experten:"

von Oliver S. (oliverso)


Lesenswert?

Martin M. schrieb:
> War so weit kein Problem nur in
> int16_t rc = _png.open(PngName.c_str(), pngOpen, pngClose, pngRead,
> pngSeek, pngDraw); hat der Compiler ein Problem die Callbacks zu
> compilen.

Funktionspointer auf Memberfunktionen sind etwas, was man sich im C++ 
Buch ganz genau anschauen muß, und dann am besten auch noch verstehen 
sollte, warum das so ist, wie es ist.

Kurzfassung: Geht so nicht.

Oliver

von Walter T. (nicolas)


Lesenswert?

Jens K. schrieb:
> ja, hat er! Siehe:
> Beitrag "Frage an die STM32-Experten:"

192 KiB RAM. Für ein Bild 320x240 Pixel bräuchte er schon 300 KiB nur 
für die entpackte Bitmap.

Ich habe den PNG-Standard damals nur oberflächlich gelesen, aber für 
mich sah das nicht so aus, als ließe sich das Entpacken in mehrere 
Teilbitmaps aufteilen.

(Ich habe es damals deshalb aufgegeben und mit für BMP entschieden. 
Dessen RLE-Komprimierung geht nämlich zeilenweise zu entpacken.)

von Harald (hasanus)


Lesenswert?

Oliver S. schrieb:
> Funktionspointer auf (nicht statische) Memberfunktionen sind

hier gar nicht relevant.

 Laut https://github.com/bitbank2/PNGdec/blob/master/src/PNGdec.h sind 
die Prototypen
1
int open(const char *szFilename, PNG_OPEN_CALLBACK *pfnOpen, PNG_CLOSE_CALLBACK *pfnClose, PNG_READ_CALLBACK *pfnRead, PNG_SEEK_CALLBACK *pfnSeek, PNG_DRAW_CALLBACK *pfnDraw);
2
3
// Callback function prototypes
4
typedef int32_t (PNG_READ_CALLBACK)(PNGFILE *pFile, uint8_t *pBuf, int32_t iLen);
5
typedef int32_t (PNG_SEEK_CALLBACK)(PNGFILE *pFile, int32_t iPosition);
6
typedef void * (PNG_OPEN_CALLBACK)(const char *szFilename, int32_t *pFileSize);
7
typedef void (PNG_DRAW_CALLBACK)(PNGDRAW *);
8
typedef void (PNG_CLOSE_CALLBACK)(void *pHandle);

Die callbacks sind auch für C verwendbar. Um zu C++ kompatibel zu sein, 
dürfen sie also keine pointer auf nichtstatische Memberfunktionen sein.

Du musst also die callbacks in deine Klasse statisch machen:
static void * pngOpen(const char *filename, int32_t *size);

von Martin M. (ats3788)


Angehängte Dateien:

Lesenswert?

Oh Danke
und Entschuldigung für das Durcheinander
Ich habe mal den Header eingefügt so wie es funktioniert, nur leider mag 
mein ESP32 den Code nicht

>c:/users/ats37/.platformio/packages/toolchain-xtensa-esp32/bin/../lib/g 
cc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: 
.pio\build\cyd\firmware.elf section `.dram0.bss' will not fit in region 
`dram0_0_seg'
>c:/users/ats37/.platformio/packages/toolchain-xtensa-esp32/bin/../lib/g 
cc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe:  DRAM segment 
data does not fit.
>c:/users/ats37/.platformio/packages/toolchain-xtensa-esp32/bin/../lib/g 
cc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe:  DRAM segment 
data does not fit.
>c:/users/ats37/.platformio/packages/toolchain-xtensa-esp32/bin/../lib/g 
cc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe:  region 
`dram0_0_seg' overflowed by 14992 bytes

von Martin M. (ats3788)


Angehängte Dateien:

Lesenswert?

Hallo
ich füge mal das cpp an. Hat mit weitere ....
nicht funktioniert.

von Michael B. (laberkopp)


Lesenswert?

Martin M. schrieb:
> nur leider mag mein ESP32 den Code nicht

Hast du mal die Fehlermeldungen gelesen ?

Offenbar genau so wenig wie die Hinweise hier im thread.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Harald schrieb:
> Du musst also die callbacks in deine Klasse statisch machen

Klingt einfach, aber statische Methoden haben keinen Zugriff auf 
dynamische Daten der Objekt-Instanz. Damit ergibt das Umschreiben nur in 
sehr wenigen speziellen Fällen Sinn.

: Bearbeitet durch User
von Matthias D. (marvin42)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> Klingt einfach, aber statische Methoden haben keinen Zugriff auf
> dynamische Daten der Objekt-Instanz

das ist kein Problem, wenn man einer statischen Methode einfach den 
Pointer auf das jeweilige Objekt übergibt, jeder C++-Wrapper macht das 
so.

die statische Methode wird zB so erweitert:

static void * pngOpen(const char *filename, int32_t *size, void* pClass)
{
  PngClass* pC = reinterpret_cast<PngClass*>(pClass);
  // jetzt kann man per pC-> auf Member+Attribute der Klasse zugreifen
}

von Oliver S. (oliverso)


Lesenswert?

Matthias D. schrieb:
> die statische Methode wird zB so erweitert:

Und entspricht damit nicht mehr der erwarteten Signatur. Also nur noch 
kurz die lib anpassen, und schon funktionierts  ...  oder so.

Oliver

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.