Fehlersuche in C-Source einer MicroPython-Version

Alles, was nicht direkt mit Python-Problemen zu tun hat. Dies ist auch der perfekte Platz für Jobangebote.
Antworten
Benutzeravatar
Dennis89
User
Beiträge: 1662
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

hierfür eröffne ich ein neues Thema.
Ich benutze gerade eine vorcompilierte MicroPython-Firmware von hier:
https://github.com/russhughes/st7789_mpy/tree/master

Mit der Funktion `jpg` kann man Bilder auf dem Display anzeigen lassen. Wenn ich das mit dem Bild aus dem Ordner `examples` mache, dann funktioniert das. Wenn ich mein eigenes Bild nehme, dann nicht. Ich bekomme einfach nur:

Code: Alles auswählen

Traceback (most recent call last):
  File "main.py", line 62, in <module>
  File "main.py", line 32, in main
RuntimeError: jpg prepare failed.
Die Bildeigenschaften, Größe, Auflösung, Format, habe ich in GIMP verglichen. Also von dem, das funktioniert und von dem das nicht geht.

Die Fehlermeldung ist hier definiert. Also alles was nicht ok ist, wird damit abgedeckt. Nur es gibt ein paar Schritte, die was anderes als OK zurückgeben. Die Funktion ist hier definiert. Nun würde ich gerne wissen, an welchem Punkt die Funktion aussteigt.

Ich hätte die Funktion in `st7789.c` folgendermaßen angepasst:

Code: Alles auswählen

static mp_obj_t st7789_ST7789_jpg_decode(size_t n_args, const mp_obj_t *args) {
    st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);

    static unsigned int (*input_func)(JDEC *, uint8_t *, unsigned int) = NULL;
    mp_buffer_info_t bufinfo;
    IODEV devid;

    if (mp_obj_is_type(args[1], &mp_type_bytes)) {
        mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
        devid.dataIdx = 0;
        devid.data = bufinfo.buf;
        devid.dataLen = bufinfo.len;
        input_func = buffer_in_func;
        self->fp = MP_OBJ_NULL;
    } else {
        const char *filename = mp_obj_str_get_str(args[1]);
        self->fp = mp_open(filename, "rb");
        devid.fp = self->fp;
        input_func = file_in_func;
        devid.data = MP_OBJ_NULL;
        devid.dataLen = 0;
    }
    mp_int_t x = 0, y = 0, width = 0, height = 0;

    if (n_args == 2 || n_args == 6) {
        if (n_args == 6) {
            x = mp_obj_get_int(args[2]);
            y = mp_obj_get_int(args[3]);
            width = mp_obj_get_int(args[4]);
            height = mp_obj_get_int(args[5]);
        }

        self->work = (void *)m_malloc(3100);          // Pointer to the work area

        JRESULT res;          // Result code of TJpgDec API
        JDEC jdec;            // Decompression object
        size_t bufsize = 0;

        if (input_func && (devid.fp || devid.data)) {
            // Prepare to decompress
            res = jd_prepare(&jdec, input_func, self->work, 3100, &devid);
            if (res == JDR_OK) {
                if (n_args < 6) {
                    x = 0;
                    y = 0;
                    width = jdec.width;
                    height = jdec.height;
                }
                // Initialize output device
                devid.left = x;
                devid.top = y;
                devid.right = x + width - 1;
                devid.bottom = y + height - 1;

                bufsize = 2 * width * height;
                self->i2c_buffer = m_malloc(bufsize);
                if (self->i2c_buffer) {
                    memset(self->i2c_buffer, 0xBEEF, bufsize);
                } else {
                    mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("out of memory"));
                }

                devid.fbuf = (uint8_t *)self->i2c_buffer;
                devid.wfbuf = jdec.width;
                devid.self = self;
                res = jd_decomp(&jdec, out_crop, 0);    // Start to decompress with 1/1 scaling
                if (res != JDR_OK) {
                    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("jpg decompress failed."));
                }

            } else if (res == JDR_INTR) {
                mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Interrupted by output function."));
            } else if (res == JDR_INP) {
                mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Device error or wrong termination of input stream"));
            } else if (res == JDR_MEM1) {
                mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Insufficient memory pool for the image"));
            } else if (res == JDR_MEM2) {
                mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Insufficient stream input buffer"));
            } else if (res == JDR_PAR) {
                mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Parameter error"));
            } else if (res == JDR_FMT1) {
                mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Data format error (may be damaged data)"));
            } else if (res == JDR_FMT2) {
                mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Right format but not supported"));
            } else if (res == JDR_FMT3) {
                mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Not supported JPEG standard"));
            }else {
                mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Unexcepted Error will preparing"));
            } 
            if (self->fp) {
                mp_close(self->fp);
                self->fp = MP_OBJ_NULL;
            }
        }
        m_free(self->work);     // Discard work area

        mp_obj_t result[3] = {
            mp_obj_new_bytearray(bufsize, (mp_obj_t *)self->i2c_buffer),
            mp_obj_new_int(width),
            mp_obj_new_int(height)
        };

        return mp_obj_new_tuple(3, result);
Habt ihr eine bessere Idee? In Python hätte ich vermutlich ein Wörterbuch benutzt, allerdings kann ich kein C. Die Logik müsste doch so passen? Definiert sind die `JDR_*` in `tjpgd565.h`.

Danke und Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
Dennis89
User
Beiträge: 1662
Registriert: Freitag 11. Dezember 2020, 15:13

So, da das an mehreren Stellen auftritt, habe ich eine Funktion geschrieben:

Code: Alles auswählen

static char * getErrorDescription(char response) {
    if (response == JDR_INTR) {
        return "Interrupted by output function.";
    } else if (response == JDR_INP) {
        return "Device error or wrong termination of input stream";
    } else if (response == JDR_MEM1) {
        return "Insufficient memory pool for the image";
    } else if (response == JDR_MEM2) {
        return "Insufficient stream input buffer";
    } else if (response == JDR_PAR) {
        return "Parameter error";
    } else if (response == JDR_FMT1) {
        return "Data format error (may be damaged data)";
    } else if (response == JDR_FMT2) {
        return "Right format but not supported";
    } else if (response == JDR_FMT3) {
        return "Not supported JPEG standard";
    }
    return "Unexcepted Error will preparing";
 }
Die rufe ich an der ursprünglichen Stelle von `"Unexcepted Error will preparing"` auf.

Wie geht man üblicherweise damit um? Meiner Meinung nach ist das eine Verbesserung, denn ich weiß jetzt dass mein "JPEG" nicht unterstützt wird. Wenn ich einen Forke erstelle, habe eigentlich nur ich was davon und die, die zufällig den Code bei mir finden. Da das selbst für mich nur ein paar Minuten Arbeit waren, "lohnt" sich ein PullRequest? Sonderlich gepflegt wird das Repo nicht, wenn man sich die letzten Updates anschaut.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
sparrow
User
Beiträge: 4622
Registriert: Freitag 17. April 2009, 10:28

Also ohne jetzt eingestiegen zu sein: Ein PR lohnt sich immer, wenn er ein Problem behebt.
Benutzeravatar
__blackjack__
User
Beiträge: 14264
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Dennis89: Ich würde auch sagen, das ein PR Sinn macht. Selbst wenn das Repo nicht so sehr gepflegt ist, erhöht sich damit die Sichtbarkeit von Deiner Änderung.

Ich würde da in C ein ``switch``/``case`` draus machen.
“Programming is partially an artform and, like artists, programmers will do it even if they don't get money.” — Linus Torvalds
Benutzeravatar
Dennis89
User
Beiträge: 1662
Registriert: Freitag 11. Dezember 2020, 15:13

Danke, dann werde ich das so machen.

Spiele jetzt noch etwas mit dem Display, dann ändere ich später den Code in `switch`/`case` und mache den PR.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Antworten