Skip to content

Run-length encoder/decoder

Notifications You must be signed in to change notification settings

tmct-web/bsgen_tmct

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bsgen_tmct

Bit Stream Generator - A run-length encoder/decoder (Build on .Net Core)

ランレングス圧縮伸張ツール(.Net Core)
※日本語の解説文は英文解説の後にあります。


bsgen_tmct is a tool for run-length compression and decompression of files.
In addition to run-length compression and decompression, it has the following features.

  • It can compress and decompress while converting endianness.
    It is also possible to output only endian conversion without compression/decompression.

  • The output format of the data is not only binary format, but also a format that can be included as the initial value of a C array.
    Originally, this tool was developed to put huge fixed value data into Arduino firmware.

Since run-length compression is easy to decompress, it is ideal for compressing data for inclusion in firmware.

Usage

bsgen_tmct is used from the command line. (.NET Core is required as runtime.)

The command is followed by the options and the parameters for them in order to specify the behavior. GUI is not available.

bsgen -<option> <parameter> -<option> <parameter> ...
option content
src Specifies the name of the file to be converted.
This file will be read as is in binary format.
* This option and parameter cannot be omitted.
dst Specifies the output file name after conversion.
* This option and its parameters cannot be omitted.
iw Specifies the data width of the file to be converted. If omitted, it means that b is specified.
b ... Single byte (1 byte)
w ... Double byte (2 bytes, so-called word)
l ... Quad byte (4 bytes, so-called long)
ie Specifies the endianness of the file to be converted. It is valid only when w or l is specified in the -iw option.
If it is omitted, b is specified.
b ... Big endian
l ... Little-endian
enc Specifies the compression/decompression type. If omitted, it means raw is specified.
raw ... No compression/decompression
rle ... Run-length compression
rld ... Run-length decompression
oe Specifies the endianness of the output file after conversion. It is valid only when w or l is specified in the -iw option.
If it is omitted, b is assumed to be specified.
b ... Big endian
l ... Little-endian
df Specifies the format of the output file after conversion. If omitted, inc is specified.
inc ... Format that can be included as the initial array value in the C language (comma-separated data)
bin ... Binary format

If you start the program without specifying any options, or if you do not specify enough options, the usage instructions will be displayed with error messages.

Example usage

To output the source file source.txt to dest.inc in run-length compressed and includable format, specify the following options and parameters.

-src source.txt -dst dest.inc -iw b -ie b -oe b -enc rle -df inc

The execution method of the command itself should follow the compiled process.
For example, if you compile with VSCode and run debug, you may need to change launch.json.

How to include as the initial value of an array

The file generated by bsgen_tmct(that can be included from the C language) is a comma-separated hexadecimal data string as shown below.

0x01,0x23,0x01,0x57,0x17,0x55,0x02,0x56,0x09,0x55,0x01,0x57,0x04,0x48,0x1c,0x4d,
0x01,0x48,0x01,0x4d,0x01,0x48,0x09,0x4d,0x03,0x48,0x04,0x4d,0x04,0x48,0x02,0x4d,
:
:

To use this as the initial value of an array from the C language, write the following in the C program source code.
The following is an example of setting dest.inc as the initial value in the unsigned char type array binary[].

const unsigned char binary[] = {
  #include "dest.inc"
};

When using the Arduino, binary[] will be a read-only array, but it will be allocated in RAM.
To use it in Flash ROM, change the file name to dest.h and add the following to the source code.

const PROGMEM unsigned char binary[] = {
  #include "dest.h"
};

How to run-length decompression

Extracting (decompressing) the original data from run-length compressed data is easy.
Here is an example code on Arduino.

unsigned int dataPointer;
unsigned int i;
unsigned char runLength;
unsigned char runData;

dataPointer = 0;

while (sizeof(binary) > dataPointer)
{
  runLength = pgm_read_byte_near(binary + dataPointer);
  dataPointer++;
  if (sizeof(binary) == dataPointer)
  {
    // Invalid data
    Serial.println(F("!!Invalid!!"));
  }
  else
  {
    runData = pgm_read_byte_near(binary + dataPointer);
    dataPointer++;
    for (i = 0; i < runLength; i++)
    {
      Serial.write(runData);
    }
  }
}

When compression efficiency is not improved

Run-length compression reduces the amount of information (= compression) by recording the original data and the number of data, for example, "AAAAAAABBBBBBBBBBCCCC" to "A×6, B×10, C×4".
The more consecutive the same data is, the higher the compression efficiency becomes, but conversely, if the data changes frequently, the data size may become larger than before compression.

In such cases, it is necessary to consider a different compression method or review the data.

Development environment

bsgen_tmct is developed in .NET Core 5 + VSCode. Since it does not use any features that deviate from the language specification or are version specific, it can be compiled in any environment that can use.

Publish an executable binary

When you do a debug build with VSCode, only DLLs will be generated.
Since there are not many people who are okay with this, if you want to generate an executable binary, type the following from the VSCode terminal.

Arch. Command line
Windows x64 dotnet publish -c Release -r win-x64 /p:PublishSingleFile=true
Windows x86 dotnet publish -c Release -r win-x86 /p:PublishSingleFile=true
MacOS dotnet publish -c Release -r osx-x64 /p:PublishSingleFile=true
* To run on Apple silicon, Rosetta2 is required.
Linux x64 dotnet publish -c Release -r linux-x64 /p:PublishSingleFile=true

By changing the parameter part of the -r option, you can generate binaries that work in various environments.
See the .NET RID Catalog for the types of options that can be specified.


bsgen_tmctはファイルをランレングス圧縮・伸張するためのツールです。
ただランレングス圧縮伸張するだけでなく、以下のような特徴があります。

  • エンディアンを変換しながら圧縮伸張できます。
    圧縮伸張なしでエンディアン変換だけを行って出力することもできます。

  • データの出力形式はバイナリ形式だけでなく、C言語の配列の初期値としてinclude可能な形式も選べます。
    元々このツールは巨大な固定値データをArduinoのファームウェアに入れ込むために開発されました。

ランレングス圧縮は伸張処理が容易なのでちょっとしたデータを圧縮してファームウェアに組み込むには最適です。

使い方

bsgen_tmctはコマンドラインから利用します。(ランタイムとして .NET Coreが必要)
オプションとそれに対するパラメータを順に並べることで動作を指定します。GUIはありません。

bsgen -<option> <parameter> -<option> <parameter> ...
option 内容
src 変換もとのファイル名を指定します。
このファイルがそのままバイナリ形式のファイルとして読み込まれます。
※このオプションとパラメータは省略できません。
dst 変換後の出力ファイル名を指定します。
※このオプションとパラメータは省略できません。
iw 変換もとのファイルのデータ幅を指定します。省略すると b を指定したことになります。
b ... シングルバイト(1バイト)
w ... ダブルバイト(2バイト、いわゆるword)
l ... クワッドバイト(4バイト、いわゆるlong)
ie 変換もとファイルのエンディアンを指定します。-iw オプションで w または l を指定した場合のみ有効です。
また、省略した場合は b を指定したことになります。
b ... ビッグエンディアン
l ... リトルエンディアン
enc 圧縮伸張タイプを指定します。省略すると raw を指定したことになります。
raw ... 圧縮伸張しない
rle ... ランレングス圧縮
rld ... ランレングス伸張
oe 変換後の出力ファイルのエンディアンを指定します。-iw オプションで w または l を指定した場合のみ有効です。
また、省略した場合は b を指定したことになります。
b ... ビッグエンディアン
l ... リトルエンディアン
df 変換後の出力ファイルのフォーマットを指定します。省略すると inc を指定したことになります。
inc ... C言語で配列初期値としてinclude可能な形式(カンマ区切りデータ)
bin ... バイナリ形式

何もオプションを指定せず起動した場合や、オプション指定が足りない場合はエラーメッセージと共に使用方法が表示されます。

使用例

変換もとファイル source.txt を ランレングス圧縮してinclude可能な形式として dest.inc に出力するには、以下のようなオプションとパラメータを指定します。

-src source.txt -dst dest.inc -iw b -ie b -oe b -enc rle -df inc

コマンド自体の実行方法はコンパイルした処理に従ってください。
たとえばVSCodeでコンパイルしてデバッグ実行する場合は launch.json を変更する必要があるでしょう。

配列の初期値としてincludeするには

bsgen_tmctで生成される、C言語からinclude可能なファイルは以下のようにカンマ区切りの16進数データ列です。

0x01,0x23,0x01,0x57,0x17,0x55,0x02,0x56,0x09,0x55,0x01,0x57,0x04,0x48,0x1c,0x4d,
0x01,0x48,0x01,0x4d,0x01,0x48,0x09,0x4d,0x03,0x48,0x04,0x4d,0x04,0x48,0x02,0x4d,
:
:

これをC言語から配列の初期値として利用するには、C言語のプログラムソースコードに以下のように記述します。
以下は unsigned char 型配列 binary[] に dest.inc を初期値としてセットする例です。

const unsigned char binary[] = {
  #include "dest.inc"
};

Arduinoで利用する場合、上記の記述だと binary[] は読み取り専用の配列にはなりますがRAM上に確保されてしまいます。
Flash ROM上に配置して利用するにはファイル名を dest.h に変更した後、ソースコードに以下のように記述します。

const PROGMEM unsigned char binary[] = {
  #include "dest.h"
};

ランレングス伸張するには

ランレングス圧縮されたデータから元のデータを取り出す(伸張する)のは簡単です。
以下にArduinoでのコード例を示します。

unsigned int dataPointer;
unsigned int i;
unsigned char runLength;
unsigned char runData;

dataPointer = 0;

while (sizeof(binary) > dataPointer)
{
  runLength = pgm_read_byte_near(binary + dataPointer);
  dataPointer++;
  if (sizeof(binary) == dataPointer)
  {
    // Invalid data
    Serial.println(F("!!Invalid!!"));
  }
  else
  {
    runData = pgm_read_byte_near(binary + dataPointer);
    dataPointer++;
    for (i = 0; i < runLength; i++)
    {
      Serial.write(runData);
    }
  }
}

圧縮効率が上がらない場合

ランレングス圧縮はたとえば「AAAAAABBBBBBBBBBCCCC」というデータを「A×6、B×10、C×4」のように、元データとその個数を記録することで情報量を少なく(=圧縮)します。
同じデータが連続するほど圧縮効率は上がりますが、逆にデータの変化が著しい場合は圧縮前よりデータサイズが大きくなることがあります。

その場合は別の圧縮方法を検討するか、データを見直す必要があります。

開発環境

bsgen_tmctは .NET Core 5 + VSCode で開発しています。 言語仕様を逸脱した機能・バージョン固有の機能は一切使用していないので、.NET Coreを利用可能な環境であればどのような環境でもコンパイルできるでしょう。

実行可能なバイナリを発行する

VSCodeでデバッグビルドを行う場合、DLLしか生成されません。
これでいい、という人はあまり居ないでしょうから、実行可能なバイナリを生成する場合はVSCodeのターミナルから以下のようにタイプしてください。

Arch. Command line
Windows x64 dotnet publish -c Release -r win-x64 /p:PublishSingleFile=true
Windows x86 dotnet publish -c Release -r win-x86 /p:PublishSingleFile=true
MacOS dotnet publish -c Release -r osx-x64 /p:PublishSingleFile=true
※Appleシリコン上で実行するにはRosetta2が必要です。
Linux x64 dotnet publish -c Release -r linux-x64 /p:PublishSingleFile=true

-r オプションのパラメータ部分を変更することで、様々な環境で動作するバイナリを生成することができます。
指定できるオプションの種類は .NET RIDカタログをご覧ください。

Releases

No releases published

Packages

No packages published