Lesen und decodieren Sie die .led-Datei

Ich arbeite an einem flexiblen LED-Bildschirm, der aus 20 Metern digitalem RGB-LED-Streifen mit WS2811- IC für jede LED besteht.

Ich möchte dies mit Arduino steuern, was mit FastSPI kein Problem ist. Mein Problem ist, dass ich verschiedene LED-Programme erstellen möchte (z. B. mit LedEdit 2013), die dann in *.led-Dateien exportiert werden können.

Dies ist an sich kein Problem, da ich diese Dateien bereits generiert habe. Das Problem ist, wie man die *.led-Datei liest und dekodiert? Nach dem, was ich im Internet lesen konnte (jetzt ein paar Stunden lang gesucht), bestehen die Dateien aus einer Art Header, gefolgt von Base64-codierten Informationen über die x- und y-Position der LEDs, die eingeschaltet werden sollten, und welche Farbe sie haben sollten sein (RGB-Wert 0-255, nehme ich an). Ich bin mir nicht ganz sicher, wie genau ich dieses Signal entschlüsseln und etwas wirklich Nützliches daraus machen soll?

Wenn ich nur ein paar nützliche Informationen herausholen kann, kann ich sicher meinen Ausweg programmieren, wenn ich es mit der FastSPI-Bibliothek für Arduino implementiere.

BEARBEITEN:

Ich habe zwei einfache Beispieldateien erstellt, die für euch vielleicht einfacher zu betrachten sind.

Beide bestehen aus einem einfachen 10 x 10 LED-Setup, beide nur eine Szene; eine ganz schwarz und eine ganz weiß.

Schwarz: http://www.codesmith.dk/black.led und Weiß: http://www.codesmith.dk/white.led

Zeigt die von Ihnen gepostete Beispiel-LED-Datei zufällig nur ein Muster für den ersten Frame und leer für die anderen 19?
@PeterJ Ich habe versehentlich die Beispieldatei auf meinem Server geändert. Ich habe den obigen Beitrag so geändert, dass er jetzt zwei Beispieldateien enthält: eine mit einer schwarzen LED-Szene und eine mit einer weißen LED-Szene. Was ich bisher festgestellt habe: Jede Zeile hat genau 1024 Zeichen; Die erste Zeile enthält 512 "zufällige Dinge" und 512 Zeichen, die Szeneninformationen zu sein scheinen; Wenn die Szene einheitlich ist (weiß oder schwarz), scheinen die Informationen in der Datei einheitliche Farbinformationen zu sein, die gesendet werden sollen. Trotzdem habe ich Probleme, dies als Binärcode oder Dezimalcode zu verstehen - selbst mit Base64-Decodierung ...
Da, jetzt will ich ein paar schwarze LEDs! Oh, warte, ich habe einige schwarze Leuchtdioden , die UV-Dioden.
Für mich sieht es nach reinen Binärdaten aus, ich habe es einfach gut geknackt und angefangen, eine Antwort darüber zu schreiben, dass es sich um einen Bitstream handelt, da die 0/1-Werte durch unterschiedliche Impulsbreiten bestimmt werden (es ist kein normaler SPI), aber ein paar Dinge haben nicht funktioniert Da summieren sie sich auch nicht, wenn ich mir die Bitmuster ansehe. Ich hätte sowieso für ein paar Tage keine Chance, aber wenn Sie keine Antwort bekommen, pingen Sie mich an und ich werde eine Antwort mit einem anderen Weg schreiben, ohne LedEdit zu verwenden (obwohl es ungetesteter C-Pseudocode sein wird ).
Anindo Ghosh: Was?? @PeterJ: Gestern fing es an, für mich ein wenig Sinn zu machen, aber dann plötzlich nicht mehr. Ich dachte, ob es ein Bitstream von 0/1 wäre, den ich mir anschaue, aber um Weiß zu bekommen, würde ich mir vorstellen, dass alles nur 1 ist und Schwarz nur 0 ist, was nicht der Fall ist. Außerdem scheinen die in der Datei verwendeten Zeichen bei jedem Testexport unterschiedlich zu sein. Gestern habe ich eine einfache RGBWB-Szene (je eine Szene) erstellt, die ein interessantes Muster ergab, aber immer noch nichts Brauchbares.
@PeterJ Etwas C-Pseudocode wäre absolut erstaunlich - könnte mir vielleicht in die richtige Richtung helfen.
@PeterJ Irgendwelche Neuigkeiten bezüglich des Pseudocodes? Ich habe es jetzt eine Weile gelassen, aber es macht in meinem Kopf immer noch keinen Sinn - leider ...
@Simon, ich war ein paar Tage beschäftigt und dann vergessen, ich werde morgen mal nachschauen. Es wird spät hier, aber habe eine Notiz gemacht und sollte morgen vor dieser Zeit etwas gepostet haben.

Antworten (1)

Ich hatte auch Probleme, die Struktur der .LED-Datei zu interpretieren, aber eine andere Methode wäre, eigene Bitmaps zu erstellen. Ich habe ein LED-Bild mit Microsoft Paint erstellt, unter File | Propertieshabe ich die Breite und Höhe auf 10 Pixel eingestellt, gefolgt von a File | Save Asund Auswahl 24-bit Bitmapals Typ. Wenn Sie maximal hineinzoomen, ist es einfach, Pixel einzeln auszuwählen, und Linux und Mac OSX haben viele Anwendungen, die Windows-Bitmaps schreiben können, wenn Sie ein anderes Betriebssystem verwenden.

Dann habe ich die folgende Visual C++-Befehlszeilenanwendung erstellt, um die Bitmap zu lesen und eine konstante Array-Definition zu erstellen. Es schreibt den Code in stdout, sodass Sie ihn beispielsweise mit aufrufen können bitmapconvert test.bmp > test.h. Beachten Sie, dass es verschiedene Annahmen bezüglich der Bitmap-Größe und Bit-Tiefe trifft, also in keiner Weise „Produktionscode“ ist, so dass Sie sich irgendwann näher mit dem Bitmap-Dateiformat befassen möchten.

#include "stdafx.h"
#include <stdio.h>
#include <stdint.h>

#define BITMAP_WIDTH 10
#define BITMAP_HEIGHT 10

#pragma pack (1)
struct PIXEL_DEF {
    uint8_t B, G, R;
} pixels[BITMAP_HEIGHT][BITMAP_WIDTH];

void read_bitmap_data(FILE *bmp)
{
    uint32_t data_offset, curx = 0, cury = 0;

    fseek(bmp, 10, SEEK_SET); // Skip to offset to bitmap bits
    fread(&data_offset, sizeof(data_offset), 1, bmp);
    fseek(bmp, data_offset, SEEK_SET); // Move to start of bits
    while (fread(&pixels[cury][curx], sizeof(PIXEL_DEF), 1, bmp))
    {
        curx++;
        if (curx >= BITMAP_WIDTH)
        {
            // Rows padded to 4 bytes, so we may need to skip some data
            fseek(bmp, 32 - curx * sizeof(PIXEL_DEF) % 32, SEEK_CUR);
            curx = 0;
            cury++;
        }
    }
    fclose(bmp);
}

// Following assumes top-left to bottom-right order, you may need to change
void dump_bitmap()
{
    int x, y;

    printf("const uint8_t bitmap_data[] = {\n");
    for (y=0; y < BITMAP_HEIGHT; y++)
    {
        for (x=0; x < BITMAP_WIDTH; x++)
        {
            if (x == 0)
                printf("\t");
            else
                printf(",");
            printf("0x%02X,0x%02X,0x%02X", pixels[y][x].R, pixels[y][x].G, pixels[y][x].B);
        }
        if (y < BITMAP_HEIGHT)
            printf(",");
        printf("\n");
    }
    printf("};\n");
}

int _tmain(int argc, TCHAR* argv[])
{
    FILE *bmp;

    if (argc != 2)
        printf("Usage: BitMapConvert infile.bmp");
    else {
        if (bmp = _wfopen(argv[1], _T("rb")))
        {
            read_bitmap_data(bmp);
            dump_bitmap();
        }
    }
    return 0;
}

Die 10 x 10 24-Bitmap, die ich zum Testen verwendet habe, hat das folgende Muster.

Testmuster

Die vom obigen Programm generierte Ausgabe wurde am Anfang des folgenden Pseudocodes eingefügt, der meiner Interpretation aus dem Datenblatt entspricht, wie Daten an das Gerät gesendet werden sollten. Die folgenden Verzögerungen gelten für den Low-Speed-Modus, verwenden Sie die Hälfte der Werte für High-Speed ​​(obwohl das Zurücksetzen gleich bleiben kann). Pin 7 ist für niedrige Geschwindigkeit mit VDD verbunden und für hohe Geschwindigkeit getrennt, sodass Sie überprüfen müssen, wie Ihre Hardware konfiguriert ist. Wenn möglich, ist eine niedrige Geschwindigkeit einfacher.

const uint8_t bitmap_data[] = {
    0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,
    0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0xFF,
    0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,
    0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,
    0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,
    0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,
    0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,
    0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,
    0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
    0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,
};

void send_zero()
{
    set_DI_high();
    delay_us(0.5);
    set_DI_low();
    delay_us(2);
}

void send_one()
{
    set_DI_high();
    delay_us(1.2);
    set_DI_low();
    delay_us(1.3);
}

void send_reset()
{
    set_DI_low();
    delay_us(50);
    set_DI_high();
}

void send_image()
{
    uint8_t i;

    send_reset();
    for (i=0; i < sizeof(bitmap_data); i++)
    {
        if (bitmap_data[i] & 0x80) send_one() else send_zero();
        if (bitmap_data[i] & 0x40) send_one() else send_zero();
        if (bitmap_data[i] & 0x20) send_one() else send_zero();
        if (bitmap_data[i] & 0x10) send_one() else send_zero();
        if (bitmap_data[i] & 0x08) send_one() else send_zero();
        if (bitmap_data[i] & 0x04) send_one() else send_zero();
        if (bitmap_data[i] & 0x02) send_one() else send_zero();
        if (bitmap_data[i] & 0x01) send_one() else send_zero();
    }
}

Wie Sie sehen können, ist das Protokoll kein SPI, und eine Herausforderung besteht darin, das richtige Timing innerhalb der im Datenblatt angegebenen +/- 150 ns zu finden, was etwa 1 Zyklus bei 8 MHz entspricht. Anstatt irgendeine Form von zu verwenden, delay_usmüssen Sie wahrscheinlich nopAnweisungen verwenden und Zeitverzögerungen berücksichtigen, die durch das Setzen der Ports und Funktionsaufrufe usw. verursacht werden. Manchmal kann es in dieser Hinsicht nützlich sein, die Assembler-Ausgabe des Compilers zu untersuchen, und ein Bereich ist immer nützlich um es zu verifizieren. Das Datenblatt scheint den gleichen 150-nS-Wert für den Niedrig- und den Hochgeschwindigkeitsmodus zu zeigen. Es kann sein, dass es im Low-Speed-Modus in der Praxis etwas weniger kritisch ist.

Allerdings habe ich mir gerade die von Ihnen erwähnte FastSPI-Bibliothek angesehen und sie erwähnt die Unterstützung für dieses Gerät. Es scheint den SPI-Kanal auf eine nicht standardmäßige Weise zu verwenden (nicht, dass es damit ein Problem gibt), um die Zeitbeschränkungen zu verringern. Ein guter Ausgangspunkt wäre also, dies in Kombination mit der obigen Bitmap-Tabelle zu verwenden.

Es ist vielleicht nicht die perfekte Lösung, aber es hat mir einige Ideen für einen anderen Ansatz gegeben, bei dem Bilder verwendet werden, anstatt Standardsoftware wie LedEdit zu verwenden, um die Dateien zu erstellen. Vielen Dank für deine Zeit und Hilfe!