From f2d98af532864e0f7e515929bb5fa5ea1278dc8e Mon Sep 17 00:00:00 2001
From: Vinzenz Schroeter <vinzenz.f.s@gmail.com>
Date: Sat, 25 May 2024 11:16:37 +0200
Subject: [PATCH 01/11] rename to servicepoint, new dir structure, WIP build.rs

---
 .gitignore                                    |   1 +
 Cargo.lock                                    | 339 ++++++++++++++++--
 Cargo.toml                                    |   8 +-
 README.md                                     |  26 +-
 .../servicepoint}/Cargo.lock                  |   0
 .../servicepoint}/Cargo.toml                  |   8 +-
 .../servicepoint}/src/bit_vec.rs              |   2 +-
 .../servicepoint}/src/byte_grid.rs            |   0
 .../servicepoint}/src/c_slice.rs              |   0
 .../servicepoint}/src/command.rs              |   0
 .../servicepoint}/src/command_code.rs         |   0
 .../servicepoint}/src/compression.rs          |   0
 .../servicepoint}/src/compression_code.rs     |   0
 .../servicepoint}/src/connection.rs           |   8 +-
 .../servicepoint}/src/data_ref.rs             |   0
 .../servicepoint}/src/grid.rs                 |   2 +-
 .../servicepoint}/src/lib.rs                  |   0
 .../servicepoint}/src/packet.rs               |   0
 .../servicepoint}/src/pixel_grid.rs           |   0
 crates/servicepoint_binding_c/Cargo.toml      |  13 +
 crates/servicepoint_binding_c/build.rs        |  13 +
 .../servicepoint_binding_c}/cbindgen.toml     |   3 +
 .../servicepoint_binding_c/servicepoint.h     |   0
 crates/servicepoint_binding_c/src/lib.rs      |   0
 .../servicepoint_binding_cs}/Cargo.lock       |   0
 .../servicepoint_binding_cs}/Cargo.toml       |   5 +-
 .../servicepoint_binding_cs/ServicePoint.sln  |   2 +-
 crates/servicepoint_binding_cs/build.rs       |  19 +
 .../src/BindGen/ServicePoint.g.cs             | 286 +++++++++++++++
 .../src/BindGen/ServicePoint2.g.cs            |   4 +-
 .../servicepoint_binding_cs}/src/BitVec.cs    |   6 +-
 .../servicepoint_binding_cs}/src/ByteGrid.cs  |   6 +-
 .../servicepoint_binding_cs}/src/Command.cs   |   6 +-
 .../src/Connection.cs                         |   6 +-
 .../servicepoint_binding_cs}/src/Constants.cs |   2 +-
 .../src/GlobalUsings.cs                       |   0
 .../servicepoint_binding_cs}/src/Packet.cs    |   6 +-
 .../servicepoint_binding_cs}/src/PixelGrid.cs |   6 +-
 .../src/ServicePoint.csproj                   |  20 +-
 .../src/ServicePointExtensions.cs             |   4 +-
 .../src/SpNativeInstance.cs                   |   8 +-
 .../servicepoint_binding_cs}/src/lib.rs       |   0
 examples/announce/Cargo.toml                  |   2 +-
 examples/announce/src/main.rs                 |   2 +-
 examples/game_of_life/Cargo.toml              |   2 +-
 examples/game_of_life/src/main.rs             |   2 +-
 examples/lang_c/Cargo.toml                    |  13 +
 examples/lang_c/Makefile                      |   6 +-
 examples/lang_c/build.rs                      |   8 +
 examples/lang_c/src/lib.rs                    |   0
 examples/lang_c/{ => src}/main.c              |   2 +-
 examples/lang_cs/Program.cs                   |   4 +-
 examples/lang_cs/lang_cs.csproj               |   2 +-
 examples/moving_line/Cargo.toml               |   4 +-
 examples/moving_line/src/main.rs              |   2 +-
 examples/random_brightness/Cargo.toml         |   2 +-
 examples/random_brightness/src/main.rs        |   4 +-
 examples/wiping_clear/Cargo.toml              |   2 +-
 examples/wiping_clear/src/main.rs             |   2 +-
 servicepoint2-binding-c/generate.sh           |   4 -
 servicepoint2-binding-cs/build.rs             |  19 -
 61 files changed, 751 insertions(+), 140 deletions(-)
 rename {servicepoint2 => crates/servicepoint}/Cargo.lock (100%)
 rename {servicepoint2 => crates/servicepoint}/Cargo.toml (81%)
 rename {servicepoint2 => crates/servicepoint}/src/bit_vec.rs (99%)
 rename {servicepoint2 => crates/servicepoint}/src/byte_grid.rs (100%)
 rename {servicepoint2 => crates/servicepoint}/src/c_slice.rs (100%)
 rename {servicepoint2 => crates/servicepoint}/src/command.rs (100%)
 rename {servicepoint2 => crates/servicepoint}/src/command_code.rs (100%)
 rename {servicepoint2 => crates/servicepoint}/src/compression.rs (100%)
 rename {servicepoint2 => crates/servicepoint}/src/compression_code.rs (100%)
 rename {servicepoint2 => crates/servicepoint}/src/connection.rs (90%)
 rename {servicepoint2 => crates/servicepoint}/src/data_ref.rs (100%)
 rename {servicepoint2 => crates/servicepoint}/src/grid.rs (97%)
 rename {servicepoint2 => crates/servicepoint}/src/lib.rs (100%)
 rename {servicepoint2 => crates/servicepoint}/src/packet.rs (100%)
 rename {servicepoint2 => crates/servicepoint}/src/pixel_grid.rs (100%)
 create mode 100644 crates/servicepoint_binding_c/Cargo.toml
 create mode 100644 crates/servicepoint_binding_c/build.rs
 rename {servicepoint2-binding-c => crates/servicepoint_binding_c}/cbindgen.toml (95%)
 rename servicepoint2-binding-c/servicepoint2.h => crates/servicepoint_binding_c/servicepoint.h (100%)
 create mode 100644 crates/servicepoint_binding_c/src/lib.rs
 rename {servicepoint2-binding-cs => crates/servicepoint_binding_cs}/Cargo.lock (100%)
 rename {servicepoint2-binding-cs => crates/servicepoint_binding_cs}/Cargo.toml (53%)
 rename servicepoint2-binding-cs/ServicePoint2.sln => crates/servicepoint_binding_cs/ServicePoint.sln (94%)
 create mode 100644 crates/servicepoint_binding_cs/build.rs
 create mode 100644 crates/servicepoint_binding_cs/src/BindGen/ServicePoint.g.cs
 rename {servicepoint2-binding-cs => crates/servicepoint_binding_cs}/src/BindGen/ServicePoint2.g.cs (99%)
 rename {servicepoint2-binding-cs => crates/servicepoint_binding_cs}/src/BitVec.cs (93%)
 rename {servicepoint2-binding-cs => crates/servicepoint_binding_cs}/src/ByteGrid.cs (95%)
 rename {servicepoint2-binding-cs => crates/servicepoint_binding_cs}/src/Command.cs (96%)
 rename {servicepoint2-binding-cs => crates/servicepoint_binding_cs}/src/Connection.cs (84%)
 rename {servicepoint2-binding-cs => crates/servicepoint_binding_cs}/src/Constants.cs (95%)
 rename {servicepoint2-binding-cs => crates/servicepoint_binding_cs}/src/GlobalUsings.cs (100%)
 rename {servicepoint2-binding-cs => crates/servicepoint_binding_cs}/src/Packet.cs (88%)
 rename {servicepoint2-binding-cs => crates/servicepoint_binding_cs}/src/PixelGrid.cs (94%)
 rename servicepoint2-binding-cs/src/ServicePoint2.csproj => crates/servicepoint_binding_cs/src/ServicePoint.csproj (78%)
 rename servicepoint2-binding-cs/src/ServicePoint2Extensions.cs => crates/servicepoint_binding_cs/src/ServicePointExtensions.cs (82%)
 rename servicepoint2-binding-cs/src/Sp2NativeInstance.cs => crates/servicepoint_binding_cs/src/SpNativeInstance.cs (85%)
 rename {servicepoint2-binding-cs => crates/servicepoint_binding_cs}/src/lib.rs (100%)
 create mode 100644 examples/lang_c/Cargo.toml
 create mode 100644 examples/lang_c/build.rs
 create mode 100644 examples/lang_c/src/lib.rs
 rename examples/lang_c/{ => src}/main.c (95%)
 delete mode 100755 servicepoint2-binding-c/generate.sh
 delete mode 100644 servicepoint2-binding-cs/build.rs

diff --git a/.gitignore b/.gitignore
index bec1c54..39156e2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ target
 out
 bin
 obj
+.direnv
diff --git a/Cargo.lock b/Cargo.lock
index f8b8d84..7eed9c8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -21,9 +21,9 @@ dependencies = [
 name = "announce"
 version = "0.1.0"
 dependencies = [
- "clap",
+ "clap 4.5.4",
  "env_logger",
- "servicepoint2",
+ "servicepoint",
 ]
 
 [[package]]
@@ -75,6 +75,35 @@ dependencies = [
  "windows-sys",
 ]
 
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+
 [[package]]
 name = "bzip2"
 version = "0.4.4"
@@ -97,10 +126,29 @@ dependencies = [
 ]
 
 [[package]]
-name = "cc"
-version = "1.0.97"
+name = "cbindgen"
+version = "0.26.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
+checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49"
+dependencies = [
+ "clap 3.2.25",
+ "heck 0.4.1",
+ "indexmap",
+ "log",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "syn 1.0.109",
+ "tempfile",
+ "toml",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f"
 dependencies = [
  "jobserver",
  "libc",
@@ -113,6 +161,21 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
+[[package]]
+name = "clap"
+version = "3.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
+dependencies = [
+ "atty",
+ "bitflags 1.3.2",
+ "clap_lex 0.2.4",
+ "indexmap",
+ "strsim 0.10.0",
+ "termcolor",
+ "textwrap",
+]
+
 [[package]]
 name = "clap"
 version = "4.5.4"
@@ -131,8 +194,8 @@ checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
 dependencies = [
  "anstream",
  "anstyle",
- "clap_lex",
- "strsim",
+ "clap_lex 0.7.0",
+ "strsim 0.11.1",
 ]
 
 [[package]]
@@ -141,10 +204,19 @@ version = "4.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
 dependencies = [
- "heck",
+ "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.63",
+ "syn 2.0.65",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
+dependencies = [
+ "os_str_bytes",
 ]
 
 [[package]]
@@ -161,9 +233,9 @@ checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
 
 [[package]]
 name = "crc32fast"
-version = "1.4.0"
+version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
 dependencies = [
  "cfg-if",
 ]
@@ -201,6 +273,22 @@ dependencies = [
  "log",
 ]
 
+[[package]]
+name = "errno"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
+
 [[package]]
 name = "flate2"
 version = "1.0.30"
@@ -215,10 +303,10 @@ dependencies = [
 name = "game_of_life"
 version = "0.1.0"
 dependencies = [
- "clap",
+ "clap 4.5.4",
  "env_logger",
  "rand",
- "servicepoint2",
+ "servicepoint",
 ]
 
 [[package]]
@@ -232,24 +320,61 @@ dependencies = [
  "wasi",
 ]
 
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
 [[package]]
 name = "heck"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "humantime"
 version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
 [[package]]
 name = "is_terminal_polyfill"
 version = "1.70.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
 
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
 [[package]]
 name = "jobserver"
 version = "0.1.31"
@@ -259,11 +384,25 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "lang_c"
+version = "0.1.0"
+dependencies = [
+ "cc",
+ "servicepoint",
+]
+
 [[package]]
 name = "libc"
-version = "0.2.154"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
 
 [[package]]
 name = "log"
@@ -279,9 +418,9 @@ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.2"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
+checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae"
 dependencies = [
  "adler",
 ]
@@ -290,9 +429,9 @@ dependencies = [
 name = "moving_line"
 version = "0.1.0"
 dependencies = [
- "clap",
+ "clap 4.5.4",
  "env_logger",
- "servicepoint2",
+ "servicepoint",
 ]
 
 [[package]]
@@ -301,6 +440,12 @@ version = "1.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
+[[package]]
+name = "os_str_bytes"
+version = "6.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
+
 [[package]]
 name = "pkg-config"
 version = "0.3.30"
@@ -315,9 +460,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.82"
+version = "1.0.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
+checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
 dependencies = [
  "unicode-ident",
 ]
@@ -365,10 +510,10 @@ dependencies = [
 name = "random_brightness"
 version = "0.1.0"
 dependencies = [
- "clap",
+ "clap 4.5.4",
  "env_logger",
  "rand",
- "servicepoint2",
+ "servicepoint",
 ]
 
 [[package]]
@@ -411,15 +556,57 @@ dependencies = [
 ]
 
 [[package]]
-name = "servicepoint-binding-cs"
-version = "0.4.2"
+name = "rustix"
+version = "0.38.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
 dependencies = [
- "csbindgen",
- "servicepoint2",
+ "bitflags 2.5.0",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
 ]
 
 [[package]]
-name = "servicepoint2"
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "serde"
+version = "1.0.202"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.202"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.65",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "servicepoint"
 version = "0.4.2"
 dependencies = [
  "bzip2",
@@ -429,6 +616,27 @@ dependencies = [
  "zstd",
 ]
 
+[[package]]
+name = "servicepoint_binding_c"
+version = "0.4.2"
+dependencies = [
+ "cbindgen",
+]
+
+[[package]]
+name = "servicepoint_binding_cs"
+version = "0.4.2"
+dependencies = [
+ "csbindgen",
+ "servicepoint",
+]
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
 [[package]]
 name = "strsim"
 version = "0.11.1"
@@ -448,15 +656,51 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.63"
+version = "2.0.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
+checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106"
 dependencies = [
  "proc-macro2",
  "quote",
  "unicode-ident",
 ]
 
+[[package]]
+name = "tempfile"
+version = "3.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "rustix",
+ "windows-sys",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
+
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "unicode-ident"
 version = "1.0.12"
@@ -481,6 +725,37 @@ version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
 [[package]]
 name = "windows-sys"
 version = "0.52.0"
@@ -558,9 +833,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
 name = "wiping_clear"
 version = "0.1.0"
 dependencies = [
- "clap",
+ "clap 4.5.4",
  "env_logger",
- "servicepoint2",
+ "servicepoint",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index f5eaca7..9159b88 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,11 +1,13 @@
 [workspace]
 resolver = "2"
 members = [
-    "servicepoint2",
-    "servicepoint2-binding-cs",
+    "crates/servicepoint",
+    "crates/servicepoint_binding_c",
+    "crates/servicepoint_binding_cs",
     "examples/announce",
     "examples/game_of_life",
     "examples/moving_line",
     "examples/wiping_clear",
-    "examples/random_brightness"
+    "examples/random_brightness",
+    "examples/lang_c"
 ]
diff --git a/README.md b/README.md
index fff4a4d..b422c20 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
-# servicepoint2
+# servicepoint
 
-[![crates.io](https://img.shields.io/crates/v/servicepoint2.svg)](https://crates.io/crates/servicepoint2)
-[![Crates.io Total Downloads](https://img.shields.io/crates/d/servicepoint2)](https://crates.io/crates/servicepoint2)
-[![docs.rs](https://img.shields.io/docsrs/servicepoint2)](https://docs.rs/servicepoint2/latest/servicepoint2/)
-[![GPLv3 licensed](https://img.shields.io/crates/l/servicepoint2)](./LICENSE)
+[![crates.io](https://img.shields.io/crates/v/servicepoint.svg)](https://crates.io/crates/servicepoint)
+[![Crates.io Total Downloads](https://img.shields.io/crates/d/servicepoint)](https://crates.io/crates/servicepoint)
+[![docs.rs](https://img.shields.io/docsrs/servicepoint)](https://docs.rs/servicepoint/latest/servicepoint/)
+[![GPLv3 licensed](https://img.shields.io/crates/l/servicepoint)](./LICENSE)
 
 In [CCCB](https://berlin.ccc.de/), there is a big pixel matrix hanging on the wall. It is called  "Service Point
 Display" or "Airport Display".
@@ -23,17 +23,17 @@ This is where the library works the best.
 Any API usage accepted by the compiler in a safe context is either safe or buggy (issues welcome)
 
 ```bash
-cargo add servicepoint2
+cargo add servicepoint
 ```
 
 ```rust
 fn main() {
     // establish connection
-    let connection = servicepoint2::Connection::open("172.23.42.29:2342")
+    let connection = servicepoint::Connection::open("172.23.42.29:2342")
         .expect("connection failed");
 
     // clear screen content
-    connection.send(servicepoint2::Command::Clear.into())
+    connection.send(servicepoint::Command::Clear.into())
         .expect("send failed");
 }
 ```
@@ -54,7 +54,7 @@ The lowest common denominator. Things to keep in mind:
 
 ```c++
 #include <stdio.h>
-#include "servicepoint2.h"
+#include "servicepoint.h"
 
 int main(void) {
     sp2_Connection *connection = sp2_connection_open("localhost:2342");
@@ -87,7 +87,7 @@ Uses C bindings internally to provide a similar API to rust. Things to keep in m
 - Reading and writing to instances concurrently is not safe. Only reading concurrently is safe.
 
 ```csharp
-using ServicePoint2;
+using ServicePoint;
 
 // using statement calls Dispose() on scope exit, which frees unmanaged instances
 using var connection = Connection.Open("127.0.0.1:2342");
@@ -116,7 +116,7 @@ git submodule add https://github.com/kaesaecracker/servicepoint.git
 git commit -m "add servicepoint submodule"
 ```
 
-You can now reference `servicepoint2-bindings-cs/src/ServicePoint2.csproj` in your project.
+You can now reference `servicepoint-bindings-cs/src/ServicePoint.csproj` in your project.
 The rust library will automatically be built.
 
 Please provide more information in the form of an issue if you need the build to copy a different library file for your platform.
@@ -136,7 +136,7 @@ If you do not need compression/decompression support you can disable those featu
 In the likely case you only need one of them, you can include that one specifically.
 
 ```toml
-[dependencies.servicepoint2]
+[dependencies.servicepoint]
 git = "https://github.com/kaesaecracker/servicepoint.git"
 default-features = false
 features = ["compression-bz"]
@@ -154,7 +154,7 @@ To add yourself to the list, open a pull request.
 
 ## Where is servicepoint1?
 
-This library is a spiritual mix of a not-yet-working rust library called `servicepoint` and a bunch of working but also unfinished C# code. Because most of the API concept and a bunch of code is taken from the rust library, the result is called `servicepoint2`.
+This library is a spiritual mix of a not-yet-working rust library called `servicepoint` and a bunch of working but also unfinished C# code. Because most of the API concept and a bunch of code is taken from the rust library, the result is called `servicepoint`.
 
 ## Contributing
 
diff --git a/servicepoint2/Cargo.lock b/crates/servicepoint/Cargo.lock
similarity index 100%
rename from servicepoint2/Cargo.lock
rename to crates/servicepoint/Cargo.lock
diff --git a/servicepoint2/Cargo.toml b/crates/servicepoint/Cargo.toml
similarity index 81%
rename from servicepoint2/Cargo.toml
rename to crates/servicepoint/Cargo.toml
index 7dfa663..3991728 100644
--- a/servicepoint2/Cargo.toml
+++ b/crates/servicepoint/Cargo.toml
@@ -1,12 +1,12 @@
 [package]
-name = "servicepoint2"
+name = "servicepoint"
 version = "0.4.2"
 publish = true
 edition = "2021"
 license = "GPL-3.0-or-later"
 description = "A rust library for the CCCB Service Point Display."
-homepage = "https://docs.rs/crate/servicepoint2"
-repository = "https://github.com/kaesaecracker/servicepoint"
+homepage = "https://docs.rs/crate/servicepoint"
+repository = "https://github.com/cccb/servicepoint"
 readme = "../README.md"
 
 [lib]
@@ -20,7 +20,7 @@ zstd = { version = "0.13", optional = true }
 rust-lzma = { version = "0.6.0", optional = true }
 
 [features]
-default = ["compression_lzma"]
+default = ["compression_lzma", "c_api"]
 compression_zlib = ["dep:flate2"]
 compression_bzip2 = ["dep:bzip2"]
 compression_lzma = ["dep:rust-lzma"]
diff --git a/servicepoint2/src/bit_vec.rs b/crates/servicepoint/src/bit_vec.rs
similarity index 99%
rename from servicepoint2/src/bit_vec.rs
rename to crates/servicepoint/src/bit_vec.rs
index 27cb8b2..a21ab4a 100644
--- a/servicepoint2/src/bit_vec.rs
+++ b/crates/servicepoint/src/bit_vec.rs
@@ -72,7 +72,7 @@ impl BitVec {
     ///
     /// # Examples
     /// ```
-    ///  use servicepoint2::BitVec;
+    ///  use servicepoint::BitVec;
     ///  let mut vec = BitVec::new(8);
     ///  vec.fill(true);
     /// ```
diff --git a/servicepoint2/src/byte_grid.rs b/crates/servicepoint/src/byte_grid.rs
similarity index 100%
rename from servicepoint2/src/byte_grid.rs
rename to crates/servicepoint/src/byte_grid.rs
diff --git a/servicepoint2/src/c_slice.rs b/crates/servicepoint/src/c_slice.rs
similarity index 100%
rename from servicepoint2/src/c_slice.rs
rename to crates/servicepoint/src/c_slice.rs
diff --git a/servicepoint2/src/command.rs b/crates/servicepoint/src/command.rs
similarity index 100%
rename from servicepoint2/src/command.rs
rename to crates/servicepoint/src/command.rs
diff --git a/servicepoint2/src/command_code.rs b/crates/servicepoint/src/command_code.rs
similarity index 100%
rename from servicepoint2/src/command_code.rs
rename to crates/servicepoint/src/command_code.rs
diff --git a/servicepoint2/src/compression.rs b/crates/servicepoint/src/compression.rs
similarity index 100%
rename from servicepoint2/src/compression.rs
rename to crates/servicepoint/src/compression.rs
diff --git a/servicepoint2/src/compression_code.rs b/crates/servicepoint/src/compression_code.rs
similarity index 100%
rename from servicepoint2/src/compression_code.rs
rename to crates/servicepoint/src/compression_code.rs
diff --git a/servicepoint2/src/connection.rs b/crates/servicepoint/src/connection.rs
similarity index 90%
rename from servicepoint2/src/connection.rs
rename to crates/servicepoint/src/connection.rs
index 559cdcb..099e379 100644
--- a/servicepoint2/src/connection.rs
+++ b/crates/servicepoint/src/connection.rs
@@ -23,7 +23,7 @@ impl Connection {
     ///
     /// # Examples
     /// ```rust
-    ///  let connection = servicepoint2::Connection::open("172.23.42.29:2342")
+    ///  let connection = servicepoint::Connection::open("172.23.42.29:2342")
     ///     .expect("connection failed");
     /// ```
     pub fn open(addr: impl ToSocketAddrs + Debug) -> std::io::Result<Self> {
@@ -48,8 +48,8 @@ impl Connection {
     /// # Examples
     ///
     /// ```rust
-    ///  use servicepoint2::{Command, CompressionCode, Grid, PixelGrid};
-    /// let connection = servicepoint2::Connection::open("172.23.42.29:2342")
+    /// use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
+    /// let connection = servicepoint::Connection::open("172.23.42.29:2342")
     ///     .expect("connection failed");
     ///
     ///  // turn off all pixels
@@ -61,7 +61,7 @@ impl Connection {
     ///  pixels.fill(true);
     ///
     ///  // send pixels to display
-    ///  connection.send(Command::BitmapLinearWin(servicepoint2::Origin(0, 0), pixels, CompressionCode::Uncompressed))
+    ///  connection.send(Command::BitmapLinearWin(servicepoint::Origin(0, 0), pixels, CompressionCode::Uncompressed))
     ///     .expect("send failed");
     /// ```
     pub fn send(&self, packet: impl Into<Packet>) -> Result<(), std::io::Error> {
diff --git a/servicepoint2/src/data_ref.rs b/crates/servicepoint/src/data_ref.rs
similarity index 100%
rename from servicepoint2/src/data_ref.rs
rename to crates/servicepoint/src/data_ref.rs
diff --git a/servicepoint2/src/grid.rs b/crates/servicepoint/src/grid.rs
similarity index 97%
rename from servicepoint2/src/grid.rs
rename to crates/servicepoint/src/grid.rs
index 2660899..55cab90 100644
--- a/servicepoint2/src/grid.rs
+++ b/crates/servicepoint/src/grid.rs
@@ -35,7 +35,7 @@ pub trait Grid<T> {
     /// # Examples
     /// To avoid boxing, this example is using the concrete type `ByteGrid`.
     /// ```
-    /// use servicepoint2::{ByteGrid, Grid};
+    /// use servicepoint::{ByteGrid, Grid};
     /// fn split(grid: ByteGrid) -> (ByteGrid, ByteGrid) {
     ///     assert!(grid.width() >= 2);
     ///     let split_x = grid.width() / 2;
diff --git a/servicepoint2/src/lib.rs b/crates/servicepoint/src/lib.rs
similarity index 100%
rename from servicepoint2/src/lib.rs
rename to crates/servicepoint/src/lib.rs
diff --git a/servicepoint2/src/packet.rs b/crates/servicepoint/src/packet.rs
similarity index 100%
rename from servicepoint2/src/packet.rs
rename to crates/servicepoint/src/packet.rs
diff --git a/servicepoint2/src/pixel_grid.rs b/crates/servicepoint/src/pixel_grid.rs
similarity index 100%
rename from servicepoint2/src/pixel_grid.rs
rename to crates/servicepoint/src/pixel_grid.rs
diff --git a/crates/servicepoint_binding_c/Cargo.toml b/crates/servicepoint_binding_c/Cargo.toml
new file mode 100644
index 0000000..79ab5b9
--- /dev/null
+++ b/crates/servicepoint_binding_c/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "servicepoint_binding_c"
+version = "0.4.2"
+publish = false
+edition = "2021"
+license = "GPL-3.0-or-later"
+description = "C bindings for the servicepoint crate."
+homepage = "https://docs.rs/crate/servicepoint"
+repository = "https://github.com/cccb/servicepoint"
+readme = "../README.md"
+
+[build-dependencies]
+cbindgen = "0.26.0"
diff --git a/crates/servicepoint_binding_c/build.rs b/crates/servicepoint_binding_c/build.rs
new file mode 100644
index 0000000..6ed5849
--- /dev/null
+++ b/crates/servicepoint_binding_c/build.rs
@@ -0,0 +1,13 @@
+use std::env;
+
+use cbindgen::{generate_with_config, Config};
+
+fn main() {
+    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
+    let config = Config::from_file(crate_dir.clone() + "/cbindgen.toml").unwrap();
+    let servicepoint_dir = crate_dir.clone() + "/../servicepoint";
+
+    generate_with_config(servicepoint_dir, config)
+      .unwrap()
+      .write_to_file("servicepoint.h");
+}
diff --git a/servicepoint2-binding-c/cbindgen.toml b/crates/servicepoint_binding_c/cbindgen.toml
similarity index 95%
rename from servicepoint2-binding-c/cbindgen.toml
rename to crates/servicepoint_binding_c/cbindgen.toml
index b10b660..42d7d04 100644
--- a/servicepoint2-binding-c/cbindgen.toml
+++ b/crates/servicepoint_binding_c/cbindgen.toml
@@ -27,6 +27,9 @@ usize_is_size_t = true
 [export]
 prefix = "sp2_"
 
+[parse]
+#include = ["servicepoint"]
+
 [parse.expand]
 features = ["c-api"]
 all_features = true
diff --git a/servicepoint2-binding-c/servicepoint2.h b/crates/servicepoint_binding_c/servicepoint.h
similarity index 100%
rename from servicepoint2-binding-c/servicepoint2.h
rename to crates/servicepoint_binding_c/servicepoint.h
diff --git a/crates/servicepoint_binding_c/src/lib.rs b/crates/servicepoint_binding_c/src/lib.rs
new file mode 100644
index 0000000..e69de29
diff --git a/servicepoint2-binding-cs/Cargo.lock b/crates/servicepoint_binding_cs/Cargo.lock
similarity index 100%
rename from servicepoint2-binding-cs/Cargo.lock
rename to crates/servicepoint_binding_cs/Cargo.lock
diff --git a/servicepoint2-binding-cs/Cargo.toml b/crates/servicepoint_binding_cs/Cargo.toml
similarity index 53%
rename from servicepoint2-binding-cs/Cargo.toml
rename to crates/servicepoint_binding_cs/Cargo.toml
index 1b549cc..8cedffc 100644
--- a/servicepoint2-binding-cs/Cargo.toml
+++ b/crates/servicepoint_binding_cs/Cargo.toml
@@ -1,13 +1,14 @@
 [package]
-name = "servicepoint-binding-cs"
+name = "servicepoint_binding_cs"
 version = "0.4.2"
 edition = "2021"
+publish = false
 
 [lib]
 crate-type = ["cdylib"]
 
 [dependencies]
-servicepoint2 = { path = "../servicepoint2", features = ["c_api"] }
+servicepoint = { path = "../servicepoint", features = ["c_api"] }
 
 [build-dependencies]
 csbindgen = "1.8.0"
diff --git a/servicepoint2-binding-cs/ServicePoint2.sln b/crates/servicepoint_binding_cs/ServicePoint.sln
similarity index 94%
rename from servicepoint2-binding-cs/ServicePoint2.sln
rename to crates/servicepoint_binding_cs/ServicePoint.sln
index 5fa11f6..c505f07 100644
--- a/servicepoint2-binding-cs/ServicePoint2.sln
+++ b/crates/servicepoint_binding_cs/ServicePoint.sln
@@ -1,6 +1,6 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint2", "src/ServicePoint2.csproj", "{70EFFA3F-012A-4518-9627-466BEAE4252E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint", "src/ServicePoint.csproj", "{70EFFA3F-012A-4518-9627-466BEAE4252E}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lang-cs", "../examples/lang_cs/lang_cs.csproj", "{DA3B8B6E-993A-47DA-844B-F92AF520FF59}"
 EndProject
diff --git a/crates/servicepoint_binding_cs/build.rs b/crates/servicepoint_binding_cs/build.rs
new file mode 100644
index 0000000..23a0377
--- /dev/null
+++ b/crates/servicepoint_binding_cs/build.rs
@@ -0,0 +1,19 @@
+fn main() {
+    println!("cargo:rerun-if-changed=DOESNOTEXIST"); // rebuild every time
+    csbindgen::Builder::default()
+        .input_extern_file("../servicepoint/src/bit_vec.rs")
+        .input_extern_file("../servicepoint/src/byte_grid.rs")
+        .input_extern_file("../servicepoint/src/command.rs")
+        .input_extern_file("../servicepoint/src/compression_code.rs")
+        .input_extern_file("../servicepoint/src/connection.rs")
+        .input_extern_file("../servicepoint/src/pixel_grid.rs")
+        .input_extern_file("../servicepoint/src/lib.rs")
+        .input_extern_file("../servicepoint/src/c_slice.rs")
+        .input_extern_file("../servicepoint/src/packet.rs")
+        .csharp_dll_name("servicepoint")
+        .csharp_namespace("ServicePoint.BindGen")
+        .csharp_use_nint_types(true)
+        .csharp_class_accessibility("public")
+        .generate_csharp_file("src/BindGen/ServicePoint.g.cs")
+        .unwrap();
+}
diff --git a/crates/servicepoint_binding_cs/src/BindGen/ServicePoint.g.cs b/crates/servicepoint_binding_cs/src/BindGen/ServicePoint.g.cs
new file mode 100644
index 0000000..d138126
--- /dev/null
+++ b/crates/servicepoint_binding_cs/src/BindGen/ServicePoint.g.cs
@@ -0,0 +1,286 @@
+// <auto-generated>
+// This code is generated by csbindgen.
+// DON'T CHANGE THIS DIRECTLY.
+// </auto-generated>
+#pragma warning disable CS8500
+#pragma warning disable CS8981
+using System;
+using System.Runtime.InteropServices;
+
+
+namespace ServicePoint.BindGen
+{
+    public static unsafe partial class NativeMethods
+    {
+        const string __DllName = "servicepoint";
+
+
+
+        /// <summary>Creates a new `BitVec` instance. The returned instance has to be freed with `bit_vec_dealloc`.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern BitVec* sp2_bit_vec_new(nuint size);
+
+        /// <summary>Loads a `BitVec` from the provided data. The returned instance has to be freed with `bit_vec_dealloc`.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern BitVec* sp2_bit_vec_load(byte* data, nuint data_length);
+
+        /// <summary>Clones a `BitVec`. The returned instance has to be freed with `bit_vec_dealloc`.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern BitVec* sp2_bit_vec_clone(BitVec* @this);
+
+        /// <summary>Deallocates a `BitVec`.  Note: do not call this if the grid has been consumed in another way, e.g. to create a command.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp2_bit_vec_dealloc(BitVec* @this);
+
+        /// <summary>Gets the value of a bit from the `BitVec`.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public static extern bool sp2_bit_vec_get(BitVec* @this, nuint index);
+
+        /// <summary>Sets the value of a bit in the `BitVec`.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public static extern bool sp2_bit_vec_set(BitVec* @this, nuint index, [MarshalAs(UnmanagedType.U1)] bool value);
+
+        /// <summary>Sets the value of all bits in the `BitVec`.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp2_bit_vec_fill(BitVec* @this, [MarshalAs(UnmanagedType.U1)] bool value);
+
+        /// <summary>Gets the length of the `BitVec` in bits.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern nuint sp2_bit_vec_len(BitVec* @this);
+
+        /// <summary>Returns true if length is 0.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_is_empty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public static extern bool sp2_bit_vec_is_empty(BitVec* @this);
+
+        /// <summary>Gets an unsafe reference to the data of the `BitVec` instance.  ## Safety  The caller has to make sure to never access the returned memory after the `BitVec` instance has been consumed or manually deallocated.  Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern CByteSlice sp2_bit_vec_unsafe_data_ref(BitVec* @this);
+
+        /// <summary>Creates a new `ByteGrid` instance. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern ByteGrid* sp2_byte_grid_new(nuint width, nuint height);
+
+        /// <summary>Loads a `ByteGrid` with the specified dimensions from the provided data. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern ByteGrid* sp2_byte_grid_load(nuint width, nuint height, byte* data, nuint data_length);
+
+        /// <summary>Clones a `ByteGrid`. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern ByteGrid* sp2_byte_grid_clone(ByteGrid* @this);
+
+        /// <summary>Deallocates a `ByteGrid`.  Note: do not call this if the grid has been consumed in another way, e.g. to create a command.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp2_byte_grid_dealloc(ByteGrid* @this);
+
+        /// <summary>Get the current value at the specified position</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern byte sp2_byte_grid_get(ByteGrid* @this, nuint x, nuint y);
+
+        /// <summary>Sets the current value at the specified position</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp2_byte_grid_set(ByteGrid* @this, nuint x, nuint y, byte value);
+
+        /// <summary>Fills the whole `ByteGrid` with the specified value</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp2_byte_grid_fill(ByteGrid* @this, byte value);
+
+        /// <summary>Gets the width in pixels of the `ByteGrid` instance.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern nuint sp2_byte_grid_width(ByteGrid* @this);
+
+        /// <summary>Gets the height in pixels of the `ByteGrid` instance.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern nuint sp2_byte_grid_height(ByteGrid* @this);
+
+        /// <summary>Gets an unsafe reference to the data of the `ByteGrid` instance.  ## Safety  The caller has to make sure to never access the returned memory after the `ByteGrid` instance has been consumed or manually deallocated.  Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern CByteSlice sp2_byte_grid_unsafe_data_ref(ByteGrid* @this);
+
+        /// <summary>Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process.  Returns: pointer to command or NULL</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_try_from_packet(Packet* packet);
+
+        /// <summary>Clones a `Command` instance</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_clone(Command* original);
+
+        /// <summary>Allocates a new `Command::Clear` instance</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_clear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_clear();
+
+        /// <summary>Allocates a new `Command::HardReset` instance</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_hard_reset", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_hard_reset();
+
+        /// <summary>Allocates a new `Command::FadeOut` instance</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_fade_out", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_fade_out();
+
+        /// <summary>Allocates a new `Command::Brightness` instance</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_brightness(byte brightness);
+
+        /// <summary>Allocates a new `Command::CharBrightness` instance. The passed `ByteGrid` gets deallocated in the process.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_char_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_char_brightness(nuint x, nuint y, ByteGrid* byte_grid);
+
+        /// <summary>Allocates a new `Command::BitmapLinear` instance. The passed `BitVec` gets deallocated in the process.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_bitmap_linear(nuint offset, BitVec* bit_vec, CompressionCode compression);
+
+        /// <summary>Allocates a new `Command::BitmapLinearAnd` instance. The passed `BitVec` gets deallocated in the process.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_and", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_bitmap_linear_and(nuint offset, BitVec* bit_vec, CompressionCode compression);
+
+        /// <summary>Allocates a new `Command::BitmapLinearOr` instance. The passed `BitVec` gets deallocated in the process.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_or", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_bitmap_linear_or(nuint offset, BitVec* bit_vec, CompressionCode compression);
+
+        /// <summary>Allocates a new `Command::BitmapLinearXor` instance. The passed `BitVec` gets deallocated in the process.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_xor", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_bitmap_linear_xor(nuint offset, BitVec* bit_vec, CompressionCode compression);
+
+        /// <summary>Allocates a new `Command::Cp437Data` instance. The passed `ByteGrid` gets deallocated in the process.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_cp437_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_cp437_data(nuint x, nuint y, ByteGrid* byte_grid);
+
+        /// <summary>Allocates a new `Command::BitmapLinearWin` instance. The passed `PixelGrid` gets deallocated in the process.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_win", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp2_command_bitmap_linear_win(nuint x, nuint y, PixelGrid* byte_grid, CompressionCode compression_code);
+
+        /// <summary>Deallocates a `Command`. Note that connection_send does this implicitly, so you only need to do this if you use the library for parsing commands.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_command_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp2_command_dealloc(Command* ptr);
+
+        /// <summary>Creates a new instance of Connection. The returned instance has to be deallocated with `connection_dealloc`.  returns: NULL if connection fails or connected instance  Panics: bad string encoding</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_connection_open", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Connection* sp2_connection_open(byte* host);
+
+        /// <summary>Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_connection_send", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public static extern bool sp2_connection_send(Connection* connection, Packet* command_ptr);
+
+        /// <summary>Closes and deallocates a connection instance</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_connection_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp2_connection_dealloc(Connection* ptr);
+
+        /// <summary>Creates a new `PixelGrid` instance. The returned instance has to be freed with `pixel_grid_dealloc`.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern PixelGrid* sp2_pixel_grid_new(nuint width, nuint height);
+
+        /// <summary>Loads a `PixelGrid` with the specified dimensions from the provided data. The returned instance has to be freed with `pixel_grid_dealloc`.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern PixelGrid* sp2_pixel_grid_load(nuint width, nuint height, byte* data, nuint data_length);
+
+        /// <summary>Clones a `PixelGrid`. The returned instance has to be freed with `pixel_grid_dealloc`.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern PixelGrid* sp2_pixel_grid_clone(PixelGrid* @this);
+
+        /// <summary>Deallocates a `PixelGrid`.  Note: do not call this if the grid has been consumed in another way, e.g. to create a command.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp2_pixel_grid_dealloc(PixelGrid* @this);
+
+        /// <summary>Get the current value at the specified position</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public static extern bool sp2_pixel_grid_get(PixelGrid* @this, nuint x, nuint y);
+
+        /// <summary>Sets the current value at the specified position</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp2_pixel_grid_set(PixelGrid* @this, nuint x, nuint y, [MarshalAs(UnmanagedType.U1)] bool value);
+
+        /// <summary>Fills the whole `PixelGrid` with the specified value</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp2_pixel_grid_fill(PixelGrid* @this, [MarshalAs(UnmanagedType.U1)] bool value);
+
+        /// <summary>Gets the width in pixels of the `PixelGrid` instance.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern nuint sp2_pixel_grid_width(PixelGrid* @this);
+
+        /// <summary>Gets the height in pixels of the `PixelGrid` instance.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern nuint sp2_pixel_grid_height(PixelGrid* @this);
+
+        /// <summary>Gets an unsafe reference to the data of the `PixelGrid` instance.  ## Safety  The caller has to make sure to never access the returned memory after the `PixelGrid` instance has been consumed or manually deallocated.  Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern CByteSlice sp2_pixel_grid_unsafe_data_ref(PixelGrid* @this);
+
+        /// <summary>Turns a `Command` into a `Packet`. The command gets deallocated in the process.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_packet_from_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Packet* sp2_packet_from_command(Command* command);
+
+        /// <summary>Tries to load a `Packet` from the passed array with the specified length.  returns: NULL in case of an error, pointer to the allocated packet otherwise</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_packet_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Packet* sp2_packet_try_load(byte* data, nuint length);
+
+        /// <summary>Deallocates a `Packet`.  Note: do not call this if the instance has been consumed in another way, e.g. by sending it.</summary>
+        [DllImport(__DllName, EntryPoint = "sp2_packet_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp2_packet_dealloc(Packet* @this);
+
+
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    public unsafe partial struct BitVec
+    {
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    public unsafe partial struct ByteGrid
+    {
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    public unsafe partial struct Connection
+    {
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    public unsafe partial struct PixelGrid
+    {
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    public unsafe partial struct CByteSlice
+    {
+        public byte* start;
+        public nuint length;
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    public unsafe partial struct Packet
+    {
+    }
+
+
+    public enum Command
+    {
+        Clear,
+        HardReset,
+        FadeOut,
+        CharBrightness,
+        Brightness,
+        BitmapLegacy,
+        BitmapLinear,
+        BitmapLinearAnd,
+        BitmapLinearOr,
+        BitmapLinearXor,
+        Cp437Data,
+        BitmapLinearWin,
+    }
+
+    public enum CompressionCode : ushort
+    {
+        Uncompressed = 0,
+        Zlib = 26490,
+        Bzip2 = 25210,
+        Lzma = 27770,
+        Zstd = 31347,
+    }
+
+
+}
diff --git a/servicepoint2-binding-cs/src/BindGen/ServicePoint2.g.cs b/crates/servicepoint_binding_cs/src/BindGen/ServicePoint2.g.cs
similarity index 99%
rename from servicepoint2-binding-cs/src/BindGen/ServicePoint2.g.cs
rename to crates/servicepoint_binding_cs/src/BindGen/ServicePoint2.g.cs
index d2df47b..d138126 100644
--- a/servicepoint2-binding-cs/src/BindGen/ServicePoint2.g.cs
+++ b/crates/servicepoint_binding_cs/src/BindGen/ServicePoint2.g.cs
@@ -8,11 +8,11 @@ using System;
 using System.Runtime.InteropServices;
 
 
-namespace ServicePoint2.BindGen
+namespace ServicePoint.BindGen
 {
     public static unsafe partial class NativeMethods
     {
-        const string __DllName = "servicepoint2";
+        const string __DllName = "servicepoint";
 
 
 
diff --git a/servicepoint2-binding-cs/src/BitVec.cs b/crates/servicepoint_binding_cs/src/BitVec.cs
similarity index 93%
rename from servicepoint2-binding-cs/src/BitVec.cs
rename to crates/servicepoint_binding_cs/src/BitVec.cs
index 4d6da0b..3d61d92 100644
--- a/servicepoint2-binding-cs/src/BitVec.cs
+++ b/crates/servicepoint_binding_cs/src/BitVec.cs
@@ -1,8 +1,8 @@
-using ServicePoint2.BindGen;
+using ServicePoint.BindGen;
 
-namespace ServicePoint2;
+namespace ServicePoint;
 
-public sealed class BitVec : Sp2NativeInstance<BindGen.BitVec>
+public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
 {
     public static BitVec New(int size)
     {
diff --git a/servicepoint2-binding-cs/src/ByteGrid.cs b/crates/servicepoint_binding_cs/src/ByteGrid.cs
similarity index 95%
rename from servicepoint2-binding-cs/src/ByteGrid.cs
rename to crates/servicepoint_binding_cs/src/ByteGrid.cs
index 2c6913d..2722a68 100644
--- a/servicepoint2-binding-cs/src/ByteGrid.cs
+++ b/crates/servicepoint_binding_cs/src/ByteGrid.cs
@@ -1,9 +1,9 @@
 using System.Text;
-using ServicePoint2.BindGen;
+using ServicePoint.BindGen;
 
-namespace ServicePoint2;
+namespace ServicePoint;
 
-public sealed class ByteGrid : Sp2NativeInstance<BindGen.ByteGrid>
+public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
 {
     public static ByteGrid New(int width, int height)
     {
diff --git a/servicepoint2-binding-cs/src/Command.cs b/crates/servicepoint_binding_cs/src/Command.cs
similarity index 96%
rename from servicepoint2-binding-cs/src/Command.cs
rename to crates/servicepoint_binding_cs/src/Command.cs
index 50e5824..b25b564 100644
--- a/servicepoint2-binding-cs/src/Command.cs
+++ b/crates/servicepoint_binding_cs/src/Command.cs
@@ -1,9 +1,9 @@
 using System.Diagnostics.CodeAnalysis;
-using ServicePoint2.BindGen;
+using ServicePoint.BindGen;
 
-namespace ServicePoint2;
+namespace ServicePoint;
 
-public sealed class Command : Sp2NativeInstance<BindGen.Command>
+public sealed class Command : SpNativeInstance<BindGen.Command>
 {
     public static bool TryFromPacket(Packet packet, [MaybeNullWhen(false)] out Command command)
     {
diff --git a/servicepoint2-binding-cs/src/Connection.cs b/crates/servicepoint_binding_cs/src/Connection.cs
similarity index 84%
rename from servicepoint2-binding-cs/src/Connection.cs
rename to crates/servicepoint_binding_cs/src/Connection.cs
index 13220f3..0f95709 100644
--- a/servicepoint2-binding-cs/src/Connection.cs
+++ b/crates/servicepoint_binding_cs/src/Connection.cs
@@ -1,9 +1,9 @@
 using System.Text;
-using ServicePoint2.BindGen;
+using ServicePoint.BindGen;
 
-namespace ServicePoint2;
+namespace ServicePoint;
 
-public sealed class Connection : Sp2NativeInstance<BindGen.Connection>
+public sealed class Connection : SpNativeInstance<BindGen.Connection>
 {
     public static Connection Open(string host)
     {
diff --git a/servicepoint2-binding-cs/src/Constants.cs b/crates/servicepoint_binding_cs/src/Constants.cs
similarity index 95%
rename from servicepoint2-binding-cs/src/Constants.cs
rename to crates/servicepoint_binding_cs/src/Constants.cs
index bad08fd..9980f64 100644
--- a/servicepoint2-binding-cs/src/Constants.cs
+++ b/crates/servicepoint_binding_cs/src/Constants.cs
@@ -1,4 +1,4 @@
-namespace ServicePoint2;
+namespace ServicePoint;
 
 public static class Constants
 {
diff --git a/servicepoint2-binding-cs/src/GlobalUsings.cs b/crates/servicepoint_binding_cs/src/GlobalUsings.cs
similarity index 100%
rename from servicepoint2-binding-cs/src/GlobalUsings.cs
rename to crates/servicepoint_binding_cs/src/GlobalUsings.cs
diff --git a/servicepoint2-binding-cs/src/Packet.cs b/crates/servicepoint_binding_cs/src/Packet.cs
similarity index 88%
rename from servicepoint2-binding-cs/src/Packet.cs
rename to crates/servicepoint_binding_cs/src/Packet.cs
index e04a02d..822e601 100644
--- a/servicepoint2-binding-cs/src/Packet.cs
+++ b/crates/servicepoint_binding_cs/src/Packet.cs
@@ -1,9 +1,9 @@
 using System.Diagnostics.CodeAnalysis;
-using ServicePoint2.BindGen;
+using ServicePoint.BindGen;
 
-namespace ServicePoint2;
+namespace ServicePoint;
 
-public sealed class Packet : Sp2NativeInstance<BindGen.Packet>
+public sealed class Packet : SpNativeInstance<BindGen.Packet>
 {
     public static Packet FromCommand(Command command)
     {
diff --git a/servicepoint2-binding-cs/src/PixelGrid.cs b/crates/servicepoint_binding_cs/src/PixelGrid.cs
similarity index 94%
rename from servicepoint2-binding-cs/src/PixelGrid.cs
rename to crates/servicepoint_binding_cs/src/PixelGrid.cs
index 0a7394c..2d12f93 100644
--- a/servicepoint2-binding-cs/src/PixelGrid.cs
+++ b/crates/servicepoint_binding_cs/src/PixelGrid.cs
@@ -1,8 +1,8 @@
-using ServicePoint2.BindGen;
+using ServicePoint.BindGen;
 
-namespace ServicePoint2;
+namespace ServicePoint;
 
-public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid>
+public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
 {
     public static PixelGrid New(int width, int height)
     {
diff --git a/servicepoint2-binding-cs/src/ServicePoint2.csproj b/crates/servicepoint_binding_cs/src/ServicePoint.csproj
similarity index 78%
rename from servicepoint2-binding-cs/src/ServicePoint2.csproj
rename to crates/servicepoint_binding_cs/src/ServicePoint.csproj
index ad74039..f090283 100644
--- a/servicepoint2-binding-cs/src/ServicePoint2.csproj
+++ b/crates/servicepoint_binding_cs/src/ServicePoint.csproj
@@ -11,15 +11,15 @@
     </PropertyGroup>
 
     <PropertyGroup>
-        <PackageId>ServicePoint2</PackageId>
+        <PackageId>ServicePoint</PackageId>
         <Version>0.3.0</Version>
         <Authors>Repository Authors</Authors>
         <Company>None</Company>
-        <Product>ServicePoint2</Product>
+        <Product>ServicePoint</Product>
         <PackageTags>CCCB</PackageTags>
         <Description>
-            C# bindings for the rust crate servicepoint2. You will need a suitable native shared library to use this.
-            For documentation, see the rust documentation: https://docs.rs/servicepoint2/latest/servicepoint2/.
+            C# bindings for the rust crate servicepoint. You will need a suitable native shared library to use this.
+            For documentation, see the rust documentation: https://docs.rs/servicepoint/latest/servicepoint/.
             Note that this library is still in early development. Breaking changes are expected before 1.0 is released.
         </Description>
         <PackageReadmeFile>README.md</PackageReadmeFile>
@@ -27,11 +27,11 @@
     </PropertyGroup>
 
     <Target Name="BuildLibrary" Condition="'$(Configuration)'=='Release'" BeforeTargets="Build">
-        <Exec Command="cargo build --manifest-path ../../servicepoint2/Cargo.toml --all-features --release"/>
+        <Exec Command="cargo build --manifest-path ../../servicepoint/Cargo.toml --all-features --release"/>
     </Target>
 
     <Target Name="BuildLibrary" Condition="'$(Configuration)'=='Debug'" BeforeTargets="Build">
-        <Exec Command="cargo build --manifest-path ../../servicepoint2/Cargo.toml --all-features"/>
+        <Exec Command="cargo build --manifest-path ../../servicepoint/Cargo.toml --all-features"/>
     </Target>
 
     <Target Name="BuildBindings" Condition="'$(Configuration)'=='Release'" BeforeTargets="Build">
@@ -43,14 +43,14 @@
     </Target>
 
     <ItemGroup Condition="'$(Configuration)'=='Debug'">
-        <Content Include="../../target/debug/libservicepoint2.so" CopyToOutputDirectory="Always">
-            <Link>libservicepoint2.so</Link>
+        <Content Include="../../target/debug/libservicepoint.so" CopyToOutputDirectory="Always">
+            <Link>libservicepoint.so</Link>
         </Content>
     </ItemGroup>
 
     <ItemGroup Condition="'$(Configuration)'=='Release'">
-        <Content Include="../../target/release/libservicepoint2.so" CopyToOutputDirectory="Always">
-            <Link>libservicepoint2.so</Link>
+        <Content Include="../../target/release/libservicepoint.so" CopyToOutputDirectory="Always">
+            <Link>libservicepoint.so</Link>
         </Content>
     </ItemGroup>
 
diff --git a/servicepoint2-binding-cs/src/ServicePoint2Extensions.cs b/crates/servicepoint_binding_cs/src/ServicePointExtensions.cs
similarity index 82%
rename from servicepoint2-binding-cs/src/ServicePoint2Extensions.cs
rename to crates/servicepoint_binding_cs/src/ServicePointExtensions.cs
index e92031f..0e569ff 100644
--- a/servicepoint2-binding-cs/src/ServicePoint2Extensions.cs
+++ b/crates/servicepoint_binding_cs/src/ServicePointExtensions.cs
@@ -1,8 +1,8 @@
 using System.Diagnostics.CodeAnalysis;
 
-namespace ServicePoint2;
+namespace ServicePoint;
 
-public static class ServicePoint2Extensions
+public static class ServicePointExtensions
 {
     public static Packet IntoPacket(this Command command)
     {
diff --git a/servicepoint2-binding-cs/src/Sp2NativeInstance.cs b/crates/servicepoint_binding_cs/src/SpNativeInstance.cs
similarity index 85%
rename from servicepoint2-binding-cs/src/Sp2NativeInstance.cs
rename to crates/servicepoint_binding_cs/src/SpNativeInstance.cs
index 9b4d94a..23013c8 100644
--- a/servicepoint2-binding-cs/src/Sp2NativeInstance.cs
+++ b/crates/servicepoint_binding_cs/src/SpNativeInstance.cs
@@ -1,6 +1,6 @@
-namespace ServicePoint2;
+namespace ServicePoint;
 
-public abstract class Sp2NativeInstance<T>
+public abstract class SpNativeInstance<T>
     : IDisposable
     where T : unmanaged
 {
@@ -16,7 +16,7 @@ public abstract class Sp2NativeInstance<T>
         }
     }
 
-    private protected unsafe Sp2NativeInstance(T* instance)
+    private protected unsafe SpNativeInstance(T* instance)
     {
         ArgumentNullException.ThrowIfNull(instance);
         _instance = instance;
@@ -44,7 +44,7 @@ public abstract class Sp2NativeInstance<T>
         GC.SuppressFinalize(this);
     }
 
-    ~Sp2NativeInstance()
+    ~SpNativeInstance()
     {
         ReleaseUnmanagedResources();
     }
diff --git a/servicepoint2-binding-cs/src/lib.rs b/crates/servicepoint_binding_cs/src/lib.rs
similarity index 100%
rename from servicepoint2-binding-cs/src/lib.rs
rename to crates/servicepoint_binding_cs/src/lib.rs
diff --git a/examples/announce/Cargo.toml b/examples/announce/Cargo.toml
index ce589a0..0b9ceed 100644
--- a/examples/announce/Cargo.toml
+++ b/examples/announce/Cargo.toml
@@ -5,6 +5,6 @@ edition = "2021"
 publish = false
 
 [dependencies]
-servicepoint2 = { path = "../../servicepoint2" }
+servicepoint = { path = "../../crates/servicepoint" }
 clap = { version = "4.5", features = ["derive"] }
 env_logger = "0.11"
diff --git a/examples/announce/src/main.rs b/examples/announce/src/main.rs
index 1c9929d..a1fb81e 100644
--- a/examples/announce/src/main.rs
+++ b/examples/announce/src/main.rs
@@ -1,6 +1,6 @@
 use clap::Parser;
 
-use servicepoint2::{ByteGrid, Command, Connection, Grid, Origin};
+use servicepoint::{ByteGrid, Command, Connection, Grid, Origin};
 
 #[derive(Parser, Debug)]
 struct Cli {
diff --git a/examples/game_of_life/Cargo.toml b/examples/game_of_life/Cargo.toml
index 999e868..df05972 100644
--- a/examples/game_of_life/Cargo.toml
+++ b/examples/game_of_life/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 publish = false
 
 [dependencies]
-servicepoint2 = { path = "../../servicepoint2" }
+servicepoint = { path = "../../crates/servicepoint" }
 clap = { version = "4.5", features = ["derive"] }
 env_logger = "0.11"
 
diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs
index 04be3cd..dae06f4 100644
--- a/examples/game_of_life/src/main.rs
+++ b/examples/game_of_life/src/main.rs
@@ -3,7 +3,7 @@ use std::thread;
 use clap::Parser;
 use rand::{distributions, Rng};
 
-use servicepoint2::*;
+use servicepoint::*;
 
 #[derive(Parser, Debug)]
 struct Cli {
diff --git a/examples/lang_c/Cargo.toml b/examples/lang_c/Cargo.toml
new file mode 100644
index 0000000..5b7dc6e
--- /dev/null
+++ b/examples/lang_c/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "lang_c"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[lib]
+
+[build-dependencies]
+cc = "1.0"
+
+[dependencies]
+servicepoint = { path = "../../crates/servicepoint" }
diff --git a/examples/lang_c/Makefile b/examples/lang_c/Makefile
index 56b7f23..489db4c 100644
--- a/examples/lang_c/Makefile
+++ b/examples/lang_c/Makefile
@@ -1,8 +1,8 @@
 ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
 OUT_DIR := ${ROOT_DIR}/out
 
-SP2_DIR := ${ROOT_DIR}/../../servicepoint2
-SP2_INCLUDE := ${ROOT_DIR}/../../servicepoint2-binding-c
+SP2_DIR := ${ROOT_DIR}/../../servicepoint
+SP2_INCLUDE := ${ROOT_DIR}/../../servicepoint-binding-c
 SP2_TARGET_RELEASE := ${SP2_DIR}/target/release
 
 .PHONY: build run clean
@@ -19,4 +19,4 @@ clean:
 ${OUT_DIR}/lang_c: main.c
 	cd ${SP2_DIR} && cargo build --release --all-features
 	mkdir -p ${OUT_DIR}
-	gcc main.c -I ${SP2_INCLUDE} -L ${SP2_TARGET_RELEASE} -Wl,-Bstatic -lservicepoint2 -Wl,-Bdynamic -o ${OUT_DIR}/lang_c
\ No newline at end of file
+	gcc main.c -I ${SP2_INCLUDE} -L ${SP2_TARGET_RELEASE} -Wl,-Bstatic -lservicepoint -Wl,-Bdynamic -o ${OUT_DIR}/lang_c
diff --git a/examples/lang_c/build.rs b/examples/lang_c/build.rs
new file mode 100644
index 0000000..ff2c59c
--- /dev/null
+++ b/examples/lang_c/build.rs
@@ -0,0 +1,8 @@
+
+fn main() {
+    println!("cargo::rerun-if-changed=src/main.c");
+
+    cc::Build::new()
+        .file("src/main.c")
+        .compile("lang_c");
+}
diff --git a/examples/lang_c/src/lib.rs b/examples/lang_c/src/lib.rs
new file mode 100644
index 0000000..e69de29
diff --git a/examples/lang_c/main.c b/examples/lang_c/src/main.c
similarity index 95%
rename from examples/lang_c/main.c
rename to examples/lang_c/src/main.c
index cf4fcff..7077eff 100644
--- a/examples/lang_c/main.c
+++ b/examples/lang_c/src/main.c
@@ -1,5 +1,5 @@
 #include <stdio.h>
-#include "servicepoint2.h"
+#include "servicepoint.h"
 
 int main(void) {
     sp2_Connection *connection = sp2_connection_open("localhost:2342");
diff --git a/examples/lang_cs/Program.cs b/examples/lang_cs/Program.cs
index 718cee3..adfc32e 100644
--- a/examples/lang_cs/Program.cs
+++ b/examples/lang_cs/Program.cs
@@ -1,5 +1,5 @@
-using ServicePoint2;
-using CompressionCode = ServicePoint2.BindGen.CompressionCode;
+using ServicePoint;
+using CompressionCode = ServicePoint.BindGen.CompressionCode;
 
 using var connection = Connection.Open("127.0.0.1:2342");
 
diff --git a/examples/lang_cs/lang_cs.csproj b/examples/lang_cs/lang_cs.csproj
index b7d2828..d4fed5f 100644
--- a/examples/lang_cs/lang_cs.csproj
+++ b/examples/lang_cs/lang_cs.csproj
@@ -9,7 +9,7 @@
     </PropertyGroup>
 
     <ItemGroup>
-        <ProjectReference Include="..\..\servicepoint2-binding-cs\src\ServicePoint2.csproj"/>
+        <ProjectReference Include="..\..\servicepoint-binding-cs\src\ServicePoint.csproj"/>
     </ItemGroup>
 
 </Project>
diff --git a/examples/moving_line/Cargo.toml b/examples/moving_line/Cargo.toml
index 4397611..23645de 100644
--- a/examples/moving_line/Cargo.toml
+++ b/examples/moving_line/Cargo.toml
@@ -5,6 +5,6 @@ edition = "2021"
 publish = false
 
 [dependencies]
-servicepoint2 = { path = "../../servicepoint2" }
+servicepoint = { path = "../../crates/servicepoint" }
 clap = { version = "4.5", features = ["derive"] }
-env_logger = "0.11"
\ No newline at end of file
+env_logger = "0.11"
diff --git a/examples/moving_line/src/main.rs b/examples/moving_line/src/main.rs
index 6ec9f1b..5e812f7 100644
--- a/examples/moving_line/src/main.rs
+++ b/examples/moving_line/src/main.rs
@@ -2,7 +2,7 @@ use std::thread;
 
 use clap::Parser;
 
-use servicepoint2::*;
+use servicepoint::*;
 
 #[derive(Parser, Debug)]
 struct Cli {
diff --git a/examples/random_brightness/Cargo.toml b/examples/random_brightness/Cargo.toml
index 479af50..4330960 100644
--- a/examples/random_brightness/Cargo.toml
+++ b/examples/random_brightness/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 publish = false
 
 [dependencies]
-servicepoint2 = { path = "../../servicepoint2" }
+servicepoint = { path = "../../crates/servicepoint" }
 clap = { version = "4.5", features = ["derive"] }
 env_logger = "0.11"
 
diff --git a/examples/random_brightness/src/main.rs b/examples/random_brightness/src/main.rs
index aa0d1f6..b4194e8 100644
--- a/examples/random_brightness/src/main.rs
+++ b/examples/random_brightness/src/main.rs
@@ -3,8 +3,8 @@ use std::time::Duration;
 use clap::Parser;
 use rand::Rng;
 
-use servicepoint2::Command::{BitmapLinearWin, Brightness, CharBrightness};
-use servicepoint2::*;
+use servicepoint::Command::{BitmapLinearWin, Brightness, CharBrightness};
+use servicepoint::*;
 
 #[derive(Parser, Debug)]
 struct Cli {
diff --git a/examples/wiping_clear/Cargo.toml b/examples/wiping_clear/Cargo.toml
index 1135b9c..7ba5c58 100644
--- a/examples/wiping_clear/Cargo.toml
+++ b/examples/wiping_clear/Cargo.toml
@@ -5,6 +5,6 @@ edition = "2021"
 publish = false
 
 [dependencies]
-servicepoint2 = { path = "../../servicepoint2" }
+servicepoint = { path = "../../crates/servicepoint" }
 clap = { version = "4.5", features = ["derive"] }
 env_logger = "0.11"
diff --git a/examples/wiping_clear/src/main.rs b/examples/wiping_clear/src/main.rs
index 08131b6..7e5d0be 100644
--- a/examples/wiping_clear/src/main.rs
+++ b/examples/wiping_clear/src/main.rs
@@ -3,7 +3,7 @@ use std::time::Duration;
 
 use clap::Parser;
 
-use servicepoint2::*;
+use servicepoint::*;
 
 #[derive(Parser, Debug)]
 struct Cli {
diff --git a/servicepoint2-binding-c/generate.sh b/servicepoint2-binding-c/generate.sh
deleted file mode 100755
index 9ccb70a..0000000
--- a/servicepoint2-binding-c/generate.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env sh
-
-# if the script crashes here, run `cargo install cbindgen`
-cbindgen --config cbindgen.toml --clean --output servicepoint2.h ../servicepoint2
diff --git a/servicepoint2-binding-cs/build.rs b/servicepoint2-binding-cs/build.rs
deleted file mode 100644
index 333066b..0000000
--- a/servicepoint2-binding-cs/build.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=DOESNOTEXIST"); // rebuild every time
-    csbindgen::Builder::default()
-        .input_extern_file("../servicepoint2/src/bit_vec.rs")
-        .input_extern_file("../servicepoint2/src/byte_grid.rs")
-        .input_extern_file("../servicepoint2/src/command.rs")
-        .input_extern_file("../servicepoint2/src/compression_code.rs")
-        .input_extern_file("../servicepoint2/src/connection.rs")
-        .input_extern_file("../servicepoint2/src/pixel_grid.rs")
-        .input_extern_file("../servicepoint2/src/lib.rs")
-        .input_extern_file("../servicepoint2/src/c_slice.rs")
-        .input_extern_file("../servicepoint2/src/packet.rs")
-        .csharp_dll_name("servicepoint2")
-        .csharp_namespace("ServicePoint2.BindGen")
-        .csharp_use_nint_types(true)
-        .csharp_class_accessibility("public")
-        .generate_csharp_file("src/BindGen/ServicePoint2.g.cs")
-        .unwrap();
-}

From edcad6fd03cd923d6cab624a7283ea4a76d19721 Mon Sep 17 00:00:00 2001
From: Vinzenz Schroeter <vinzenz.f.s@gmail.com>
Date: Sun, 26 May 2024 11:40:52 +0200
Subject: [PATCH 02/11] improve c build

---
 Cargo.lock                                    |   2 +-
 crates/servicepoint/Cargo.toml                |   2 +-
 crates/servicepoint_binding_c/Cargo.toml      |   3 +-
 crates/servicepoint_binding_c/build.rs        |  23 +-
 crates/servicepoint_binding_cs/Cargo.toml     |   1 +
 .../src/BindGen/ServicePoint2.g.cs            | 286 ------------------
 examples/lang_c/Cargo.toml                    |   4 +-
 examples/lang_c/Makefile                      |  48 +--
 examples/lang_c/build.rs                      |  15 +-
 .../lang_c/include}/servicepoint.h            |   0
 shell.nix                                     |  13 +-
 11 files changed, 77 insertions(+), 320 deletions(-)
 delete mode 100644 crates/servicepoint_binding_cs/src/BindGen/ServicePoint2.g.cs
 rename {crates/servicepoint_binding_c => examples/lang_c/include}/servicepoint.h (100%)

diff --git a/Cargo.lock b/Cargo.lock
index 7eed9c8..2dac4bc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -389,7 +389,7 @@ name = "lang_c"
 version = "0.1.0"
 dependencies = [
  "cc",
- "servicepoint",
+ "servicepoint_binding_c",
 ]
 
 [[package]]
diff --git a/crates/servicepoint/Cargo.toml b/crates/servicepoint/Cargo.toml
index 3991728..8e7fb65 100644
--- a/crates/servicepoint/Cargo.toml
+++ b/crates/servicepoint/Cargo.toml
@@ -7,7 +7,7 @@ license = "GPL-3.0-or-later"
 description = "A rust library for the CCCB Service Point Display."
 homepage = "https://docs.rs/crate/servicepoint"
 repository = "https://github.com/cccb/servicepoint"
-readme = "../README.md"
+readme = "../../README.md"
 
 [lib]
 crate-type = ["staticlib", "rlib", "cdylib"]
diff --git a/crates/servicepoint_binding_c/Cargo.toml b/crates/servicepoint_binding_c/Cargo.toml
index 79ab5b9..9a2cb27 100644
--- a/crates/servicepoint_binding_c/Cargo.toml
+++ b/crates/servicepoint_binding_c/Cargo.toml
@@ -7,7 +7,8 @@ license = "GPL-3.0-or-later"
 description = "C bindings for the servicepoint crate."
 homepage = "https://docs.rs/crate/servicepoint"
 repository = "https://github.com/cccb/servicepoint"
-readme = "../README.md"
+readme = "../../README.md"
+links = "servicepoint"
 
 [build-dependencies]
 cbindgen = "0.26.0"
diff --git a/crates/servicepoint_binding_c/build.rs b/crates/servicepoint_binding_c/build.rs
index 6ed5849..f5e4607 100644
--- a/crates/servicepoint_binding_c/build.rs
+++ b/crates/servicepoint_binding_c/build.rs
@@ -1,13 +1,28 @@
-use std::env;
+use std::{env, fs::copy};
 
 use cbindgen::{generate_with_config, Config};
 
 fn main() {
     let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
-    let config = Config::from_file(crate_dir.clone() + "/cbindgen.toml").unwrap();
+    println!("cargo::rerun-if-changed={crate_dir}");
+
+    let config =
+        Config::from_file(crate_dir.clone() + "/cbindgen.toml").unwrap();
     let servicepoint_dir = crate_dir.clone() + "/../servicepoint";
 
+    let output_dir = env::var("OUT_DIR").unwrap();
+    let header_file = output_dir.clone() + "/servicepoint.h";
+
     generate_with_config(servicepoint_dir, config)
-      .unwrap()
-      .write_to_file("servicepoint.h");
+        .unwrap()
+        .write_to_file(&header_file);
+    println!("cargo:include={output_dir}");
+
+    println!("cargo::rerun-if-env-changed=SERVICEPOINT_HEADER_OUT");
+    if let Ok(header_out) = env::var("SERVICEPOINT_HEADER_OUT") {
+        let header_copy = header_out + "/servicepoint.h";
+        println!("cargo:warning=Copying header to {header_copy}");
+        copy(header_file, &header_copy).unwrap();
+        println!("cargo::rerun-if-changed={header_copy}");
+    }
 }
diff --git a/crates/servicepoint_binding_cs/Cargo.toml b/crates/servicepoint_binding_cs/Cargo.toml
index 8cedffc..ed651f5 100644
--- a/crates/servicepoint_binding_cs/Cargo.toml
+++ b/crates/servicepoint_binding_cs/Cargo.toml
@@ -3,6 +3,7 @@ name = "servicepoint_binding_cs"
 version = "0.4.2"
 edition = "2021"
 publish = false
+readme = "../../README.md"
 
 [lib]
 crate-type = ["cdylib"]
diff --git a/crates/servicepoint_binding_cs/src/BindGen/ServicePoint2.g.cs b/crates/servicepoint_binding_cs/src/BindGen/ServicePoint2.g.cs
deleted file mode 100644
index d138126..0000000
--- a/crates/servicepoint_binding_cs/src/BindGen/ServicePoint2.g.cs
+++ /dev/null
@@ -1,286 +0,0 @@
-// <auto-generated>
-// This code is generated by csbindgen.
-// DON'T CHANGE THIS DIRECTLY.
-// </auto-generated>
-#pragma warning disable CS8500
-#pragma warning disable CS8981
-using System;
-using System.Runtime.InteropServices;
-
-
-namespace ServicePoint.BindGen
-{
-    public static unsafe partial class NativeMethods
-    {
-        const string __DllName = "servicepoint";
-
-
-
-        /// <summary>Creates a new `BitVec` instance. The returned instance has to be freed with `bit_vec_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern BitVec* sp2_bit_vec_new(nuint size);
-
-        /// <summary>Loads a `BitVec` from the provided data. The returned instance has to be freed with `bit_vec_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern BitVec* sp2_bit_vec_load(byte* data, nuint data_length);
-
-        /// <summary>Clones a `BitVec`. The returned instance has to be freed with `bit_vec_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern BitVec* sp2_bit_vec_clone(BitVec* @this);
-
-        /// <summary>Deallocates a `BitVec`.  Note: do not call this if the grid has been consumed in another way, e.g. to create a command.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_bit_vec_dealloc(BitVec* @this);
-
-        /// <summary>Gets the value of a bit from the `BitVec`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        [return: MarshalAs(UnmanagedType.U1)]
-        public static extern bool sp2_bit_vec_get(BitVec* @this, nuint index);
-
-        /// <summary>Sets the value of a bit in the `BitVec`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        [return: MarshalAs(UnmanagedType.U1)]
-        public static extern bool sp2_bit_vec_set(BitVec* @this, nuint index, [MarshalAs(UnmanagedType.U1)] bool value);
-
-        /// <summary>Sets the value of all bits in the `BitVec`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_bit_vec_fill(BitVec* @this, [MarshalAs(UnmanagedType.U1)] bool value);
-
-        /// <summary>Gets the length of the `BitVec` in bits.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern nuint sp2_bit_vec_len(BitVec* @this);
-
-        /// <summary>Returns true if length is 0.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_is_empty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        [return: MarshalAs(UnmanagedType.U1)]
-        public static extern bool sp2_bit_vec_is_empty(BitVec* @this);
-
-        /// <summary>Gets an unsafe reference to the data of the `BitVec` instance.  ## Safety  The caller has to make sure to never access the returned memory after the `BitVec` instance has been consumed or manually deallocated.  Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern CByteSlice sp2_bit_vec_unsafe_data_ref(BitVec* @this);
-
-        /// <summary>Creates a new `ByteGrid` instance. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern ByteGrid* sp2_byte_grid_new(nuint width, nuint height);
-
-        /// <summary>Loads a `ByteGrid` with the specified dimensions from the provided data. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern ByteGrid* sp2_byte_grid_load(nuint width, nuint height, byte* data, nuint data_length);
-
-        /// <summary>Clones a `ByteGrid`. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern ByteGrid* sp2_byte_grid_clone(ByteGrid* @this);
-
-        /// <summary>Deallocates a `ByteGrid`.  Note: do not call this if the grid has been consumed in another way, e.g. to create a command.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_byte_grid_dealloc(ByteGrid* @this);
-
-        /// <summary>Get the current value at the specified position</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern byte sp2_byte_grid_get(ByteGrid* @this, nuint x, nuint y);
-
-        /// <summary>Sets the current value at the specified position</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_byte_grid_set(ByteGrid* @this, nuint x, nuint y, byte value);
-
-        /// <summary>Fills the whole `ByteGrid` with the specified value</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_byte_grid_fill(ByteGrid* @this, byte value);
-
-        /// <summary>Gets the width in pixels of the `ByteGrid` instance.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern nuint sp2_byte_grid_width(ByteGrid* @this);
-
-        /// <summary>Gets the height in pixels of the `ByteGrid` instance.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern nuint sp2_byte_grid_height(ByteGrid* @this);
-
-        /// <summary>Gets an unsafe reference to the data of the `ByteGrid` instance.  ## Safety  The caller has to make sure to never access the returned memory after the `ByteGrid` instance has been consumed or manually deallocated.  Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern CByteSlice sp2_byte_grid_unsafe_data_ref(ByteGrid* @this);
-
-        /// <summary>Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process.  Returns: pointer to command or NULL</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_try_from_packet(Packet* packet);
-
-        /// <summary>Clones a `Command` instance</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_clone(Command* original);
-
-        /// <summary>Allocates a new `Command::Clear` instance</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_clear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_clear();
-
-        /// <summary>Allocates a new `Command::HardReset` instance</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_hard_reset", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_hard_reset();
-
-        /// <summary>Allocates a new `Command::FadeOut` instance</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_fade_out", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_fade_out();
-
-        /// <summary>Allocates a new `Command::Brightness` instance</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_brightness(byte brightness);
-
-        /// <summary>Allocates a new `Command::CharBrightness` instance. The passed `ByteGrid` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_char_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_char_brightness(nuint x, nuint y, ByteGrid* byte_grid);
-
-        /// <summary>Allocates a new `Command::BitmapLinear` instance. The passed `BitVec` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_bitmap_linear(nuint offset, BitVec* bit_vec, CompressionCode compression);
-
-        /// <summary>Allocates a new `Command::BitmapLinearAnd` instance. The passed `BitVec` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_and", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_bitmap_linear_and(nuint offset, BitVec* bit_vec, CompressionCode compression);
-
-        /// <summary>Allocates a new `Command::BitmapLinearOr` instance. The passed `BitVec` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_or", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_bitmap_linear_or(nuint offset, BitVec* bit_vec, CompressionCode compression);
-
-        /// <summary>Allocates a new `Command::BitmapLinearXor` instance. The passed `BitVec` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_xor", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_bitmap_linear_xor(nuint offset, BitVec* bit_vec, CompressionCode compression);
-
-        /// <summary>Allocates a new `Command::Cp437Data` instance. The passed `ByteGrid` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_cp437_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_cp437_data(nuint x, nuint y, ByteGrid* byte_grid);
-
-        /// <summary>Allocates a new `Command::BitmapLinearWin` instance. The passed `PixelGrid` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_win", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_bitmap_linear_win(nuint x, nuint y, PixelGrid* byte_grid, CompressionCode compression_code);
-
-        /// <summary>Deallocates a `Command`. Note that connection_send does this implicitly, so you only need to do this if you use the library for parsing commands.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_command_dealloc(Command* ptr);
-
-        /// <summary>Creates a new instance of Connection. The returned instance has to be deallocated with `connection_dealloc`.  returns: NULL if connection fails or connected instance  Panics: bad string encoding</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_connection_open", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Connection* sp2_connection_open(byte* host);
-
-        /// <summary>Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_connection_send", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        [return: MarshalAs(UnmanagedType.U1)]
-        public static extern bool sp2_connection_send(Connection* connection, Packet* command_ptr);
-
-        /// <summary>Closes and deallocates a connection instance</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_connection_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_connection_dealloc(Connection* ptr);
-
-        /// <summary>Creates a new `PixelGrid` instance. The returned instance has to be freed with `pixel_grid_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern PixelGrid* sp2_pixel_grid_new(nuint width, nuint height);
-
-        /// <summary>Loads a `PixelGrid` with the specified dimensions from the provided data. The returned instance has to be freed with `pixel_grid_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern PixelGrid* sp2_pixel_grid_load(nuint width, nuint height, byte* data, nuint data_length);
-
-        /// <summary>Clones a `PixelGrid`. The returned instance has to be freed with `pixel_grid_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern PixelGrid* sp2_pixel_grid_clone(PixelGrid* @this);
-
-        /// <summary>Deallocates a `PixelGrid`.  Note: do not call this if the grid has been consumed in another way, e.g. to create a command.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_pixel_grid_dealloc(PixelGrid* @this);
-
-        /// <summary>Get the current value at the specified position</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        [return: MarshalAs(UnmanagedType.U1)]
-        public static extern bool sp2_pixel_grid_get(PixelGrid* @this, nuint x, nuint y);
-
-        /// <summary>Sets the current value at the specified position</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_pixel_grid_set(PixelGrid* @this, nuint x, nuint y, [MarshalAs(UnmanagedType.U1)] bool value);
-
-        /// <summary>Fills the whole `PixelGrid` with the specified value</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_pixel_grid_fill(PixelGrid* @this, [MarshalAs(UnmanagedType.U1)] bool value);
-
-        /// <summary>Gets the width in pixels of the `PixelGrid` instance.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern nuint sp2_pixel_grid_width(PixelGrid* @this);
-
-        /// <summary>Gets the height in pixels of the `PixelGrid` instance.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern nuint sp2_pixel_grid_height(PixelGrid* @this);
-
-        /// <summary>Gets an unsafe reference to the data of the `PixelGrid` instance.  ## Safety  The caller has to make sure to never access the returned memory after the `PixelGrid` instance has been consumed or manually deallocated.  Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern CByteSlice sp2_pixel_grid_unsafe_data_ref(PixelGrid* @this);
-
-        /// <summary>Turns a `Command` into a `Packet`. The command gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_packet_from_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Packet* sp2_packet_from_command(Command* command);
-
-        /// <summary>Tries to load a `Packet` from the passed array with the specified length.  returns: NULL in case of an error, pointer to the allocated packet otherwise</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_packet_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Packet* sp2_packet_try_load(byte* data, nuint length);
-
-        /// <summary>Deallocates a `Packet`.  Note: do not call this if the instance has been consumed in another way, e.g. by sending it.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_packet_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_packet_dealloc(Packet* @this);
-
-
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    public unsafe partial struct BitVec
-    {
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    public unsafe partial struct ByteGrid
-    {
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    public unsafe partial struct Connection
-    {
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    public unsafe partial struct PixelGrid
-    {
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    public unsafe partial struct CByteSlice
-    {
-        public byte* start;
-        public nuint length;
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    public unsafe partial struct Packet
-    {
-    }
-
-
-    public enum Command
-    {
-        Clear,
-        HardReset,
-        FadeOut,
-        CharBrightness,
-        Brightness,
-        BitmapLegacy,
-        BitmapLinear,
-        BitmapLinearAnd,
-        BitmapLinearOr,
-        BitmapLinearXor,
-        Cp437Data,
-        BitmapLinearWin,
-    }
-
-    public enum CompressionCode : ushort
-    {
-        Uncompressed = 0,
-        Zlib = 26490,
-        Bzip2 = 25210,
-        Lzma = 27770,
-        Zstd = 31347,
-    }
-
-
-}
diff --git a/examples/lang_c/Cargo.toml b/examples/lang_c/Cargo.toml
index 5b7dc6e..8baf474 100644
--- a/examples/lang_c/Cargo.toml
+++ b/examples/lang_c/Cargo.toml
@@ -4,10 +4,8 @@ version = "0.1.0"
 edition = "2021"
 publish = false
 
-[lib]
-
 [build-dependencies]
 cc = "1.0"
 
 [dependencies]
-servicepoint = { path = "../../crates/servicepoint" }
+servicepoint_binding_c = { path = "../../crates/servicepoint_binding_c" }
diff --git a/examples/lang_c/Makefile b/examples/lang_c/Makefile
index 489db4c..825510a 100644
--- a/examples/lang_c/Makefile
+++ b/examples/lang_c/Makefile
@@ -1,22 +1,36 @@
-ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
-OUT_DIR := ${ROOT_DIR}/out
+CC := gcc
 
-SP2_DIR := ${ROOT_DIR}/../../servicepoint
-SP2_INCLUDE := ${ROOT_DIR}/../../servicepoint-binding-c
-SP2_TARGET_RELEASE := ${SP2_DIR}/target/release
+THIS_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
+REPO_ROOT := $(THIS_DIR)/../..
 
-.PHONY: build run clean
-
-all: ${OUT_DIR}/lang_c
-
-run: ${OUT_DIR}/lang_c
-	out/lang_c
+build: out/lang_c
 
 clean:
-	rm -r ${OUT_DIR} || true
-	rm -r ${SP2_TARGET_RELEASE} || true
+	rm -r out
+	rm include/servicepoint.h
 
-${OUT_DIR}/lang_c: main.c
-	cd ${SP2_DIR} && cargo build --release --all-features
-	mkdir -p ${OUT_DIR}
-	gcc main.c -I ${SP2_INCLUDE} -L ${SP2_TARGET_RELEASE} -Wl,-Bstatic -lservicepoint -Wl,-Bdynamic -o ${OUT_DIR}/lang_c
+run: out/lang_c
+	out/lang_c
+
+PHONY: build clean dependencies run
+
+out/lang_c: dependencies src/main.c
+	mkdir out || true
+	${CC} src/main.c \
+		-I include \
+		-L $(REPO_ROOT)/target/release \
+		-Wl,-Bstatic -lservicepoint \
+		-Wl,-Bdynamic -llzma \
+		-o out/lang_c \
+
+dependencies: FORCE
+	mkdir include || true
+	# generate servicepoint header
+	SERVICEPOINT_HEADER_OUT=$(THIS_DIR)/include cargo build \
+		--manifest-path=$(REPO_ROOT)/crates/servicepoint_binding_c/Cargo.toml
+
+	# build release binary to link against
+	cargo build --manifest-path=$(REPO_ROOT)/crates/servicepoint/Cargo.toml --release \
+		--features c_api,all_compressions
+
+FORCE: ;
diff --git a/examples/lang_c/build.rs b/examples/lang_c/build.rs
index ff2c59c..56b5b89 100644
--- a/examples/lang_c/build.rs
+++ b/examples/lang_c/build.rs
@@ -1,8 +1,15 @@
-
 fn main() {
     println!("cargo::rerun-if-changed=src/main.c");
+    println!("cargo::rerun-if-changed=build.rs");
 
-    cc::Build::new()
-        .file("src/main.c")
-        .compile("lang_c");
+    let sp_include = std::env::var_os("DEP_SERVICEPOINT_INCLUDE")
+        .unwrap()
+        .into_string()
+        .unwrap();
+
+    // this builds a lib, this is only to check that the example compiles
+    let mut cc = cc::Build::new();
+    cc.file("src/main.c");
+    cc.include(&sp_include);
+    cc.compile("lang_c");
 }
diff --git a/crates/servicepoint_binding_c/servicepoint.h b/examples/lang_c/include/servicepoint.h
similarity index 100%
rename from crates/servicepoint_binding_c/servicepoint.h
rename to examples/lang_c/include/servicepoint.h
diff --git a/shell.nix b/shell.nix
index c961482..0555690 100644
--- a/shell.nix
+++ b/shell.nix
@@ -1,4 +1,11 @@
-{ pkgs ? import <nixpkgs> {} }:
-  pkgs.mkShell {
-    nativeBuildInputs = with pkgs.buildPackages; [ rustup pkg-config xe lzma cargo-tarpaulin ];
+{pkgs ? import <nixpkgs> {}}:
+pkgs.mkShell {
+  nativeBuildInputs = with pkgs.buildPackages; [
+    rustup
+    pkg-config
+    xe
+    lzma
+    cargo-tarpaulin
+    gnumake
+  ];
 }

From f759395393656b5810223a99ff14e266c43bb32a Mon Sep 17 00:00:00 2001
From: Vinzenz Schroeter <vinzenz.f.s@gmail.com>
Date: Sun, 26 May 2024 13:15:11 +0200
Subject: [PATCH 03/11] move c_api into binding_c crate, update C# binding

---
 Cargo.lock                                    |   3 +-
 crates/servicepoint/Cargo.toml                |   5 +-
 crates/servicepoint/src/bit_vec.rs            |  97 --------
 crates/servicepoint/src/byte_grid.rs          | 113 ---------
 crates/servicepoint/src/command.rs            | 173 --------------
 crates/servicepoint/src/connection.rs         |  50 +---
 crates/servicepoint/src/lib.rs                |   3 -
 crates/servicepoint/src/packet.rs             |  40 ----
 crates/servicepoint/src/pixel_grid.rs         | 112 ---------
 crates/servicepoint_binding_c/Cargo.toml      |   8 +
 crates/servicepoint_binding_c/build.rs        |   3 +-
 crates/servicepoint_binding_c/cbindgen.toml   |  17 +-
 crates/servicepoint_binding_c/src/bit_vec.rs  |  94 ++++++++
 .../servicepoint_binding_c/src/byte_grid.rs   | 103 ++++++++
 .../src/c_slice.rs                            |   1 -
 crates/servicepoint_binding_c/src/command.rs  | 166 +++++++++++++
 .../servicepoint_binding_c/src/connection.rs  |  40 ++++
 crates/servicepoint_binding_c/src/lib.rs      |  14 ++
 crates/servicepoint_binding_c/src/packet.rs   |  37 +++
 .../servicepoint_binding_c/src/pixel_grid.rs  | 102 ++++++++
 crates/servicepoint_binding_cs/Cargo.toml     |   6 +-
 .../servicepoint_binding_cs/ServicePoint.sln  |   4 +-
 .../BindGen/ServicePoint.g.cs                 | 219 +++++++++---------
 .../{src => ServicePoint}/BitVec.cs           |  18 +-
 .../{src => ServicePoint}/ByteGrid.cs         |  20 +-
 .../{src => ServicePoint}/Command.cs          |  28 +--
 .../{src => ServicePoint}/Connection.cs       |   6 +-
 .../{src => ServicePoint}/Constants.cs        |   0
 .../{src => ServicePoint}/GlobalUsings.cs     |   0
 .../{src => ServicePoint}/Packet.cs           |   6 +-
 .../{src => ServicePoint}/PixelGrid.cs        |  20 +-
 .../{src => ServicePoint}/ServicePoint.csproj |  36 ++-
 .../ServicePointExtensions.cs                 |   0
 .../{src => ServicePoint}/SpNativeInstance.cs |   0
 crates/servicepoint_binding_cs/build.rs       |  19 +-
 examples/lang_c/Makefile                      |  17 +-
 examples/lang_c/build.rs                      |  15 +-
 examples/lang_c/include/servicepoint.h        | 200 ++++++++--------
 examples/lang_c/src/main.c                    |  14 +-
 examples/lang_cs/lang_cs.csproj               |   2 +-
 40 files changed, 895 insertions(+), 916 deletions(-)
 create mode 100644 crates/servicepoint_binding_c/src/bit_vec.rs
 create mode 100644 crates/servicepoint_binding_c/src/byte_grid.rs
 rename crates/{servicepoint => servicepoint_binding_c}/src/c_slice.rs (91%)
 create mode 100644 crates/servicepoint_binding_c/src/command.rs
 create mode 100644 crates/servicepoint_binding_c/src/connection.rs
 create mode 100644 crates/servicepoint_binding_c/src/packet.rs
 create mode 100644 crates/servicepoint_binding_c/src/pixel_grid.rs
 rename crates/servicepoint_binding_cs/{src => ServicePoint}/BindGen/ServicePoint.g.cs (52%)
 rename crates/servicepoint_binding_cs/{src => ServicePoint}/BitVec.cs (63%)
 rename crates/servicepoint_binding_cs/{src => ServicePoint}/ByteGrid.cs (72%)
 rename crates/servicepoint_binding_cs/{src => ServicePoint}/Command.cs (64%)
 rename crates/servicepoint_binding_cs/{src => ServicePoint}/Connection.cs (72%)
 rename crates/servicepoint_binding_cs/{src => ServicePoint}/Constants.cs (100%)
 rename crates/servicepoint_binding_cs/{src => ServicePoint}/GlobalUsings.cs (100%)
 rename crates/servicepoint_binding_cs/{src => ServicePoint}/Packet.cs (76%)
 rename crates/servicepoint_binding_cs/{src => ServicePoint}/PixelGrid.cs (63%)
 rename crates/servicepoint_binding_cs/{src => ServicePoint}/ServicePoint.csproj (74%)
 rename crates/servicepoint_binding_cs/{src => ServicePoint}/ServicePointExtensions.cs (100%)
 rename crates/servicepoint_binding_cs/{src => ServicePoint}/SpNativeInstance.cs (100%)

diff --git a/Cargo.lock b/Cargo.lock
index 2dac4bc..55cb4e5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -621,6 +621,7 @@ name = "servicepoint_binding_c"
 version = "0.4.2"
 dependencies = [
  "cbindgen",
+ "servicepoint",
 ]
 
 [[package]]
@@ -628,7 +629,7 @@ name = "servicepoint_binding_cs"
 version = "0.4.2"
 dependencies = [
  "csbindgen",
- "servicepoint",
+ "servicepoint_binding_c",
 ]
 
 [[package]]
diff --git a/crates/servicepoint/Cargo.toml b/crates/servicepoint/Cargo.toml
index 8e7fb65..9e0905b 100644
--- a/crates/servicepoint/Cargo.toml
+++ b/crates/servicepoint/Cargo.toml
@@ -10,7 +10,7 @@ repository = "https://github.com/cccb/servicepoint"
 readme = "../../README.md"
 
 [lib]
-crate-type = ["staticlib", "rlib", "cdylib"]
+crate-type = ["rlib"]
 
 [dependencies]
 log = "0.4"
@@ -20,10 +20,9 @@ zstd = { version = "0.13", optional = true }
 rust-lzma = { version = "0.6.0", optional = true }
 
 [features]
-default = ["compression_lzma", "c_api"]
+default = ["compression_lzma"]
 compression_zlib = ["dep:flate2"]
 compression_bzip2 = ["dep:bzip2"]
 compression_lzma = ["dep:rust-lzma"]
 compression_zstd = ["dep:zstd"]
 all_compressions = ["compression_zlib", "compression_bzip2", "compression_lzma", "compression_zstd"]
-c_api = []
diff --git a/crates/servicepoint/src/bit_vec.rs b/crates/servicepoint/src/bit_vec.rs
index a21ab4a..0f3e262 100644
--- a/crates/servicepoint/src/bit_vec.rs
+++ b/crates/servicepoint/src/bit_vec.rs
@@ -135,103 +135,6 @@ impl From<&[u8]> for BitVec {
     }
 }
 
-#[cfg(feature = "c_api")]
-pub mod c_api {
-    use crate::{BitVec, CByteSlice, DataRef};
-
-    /// Creates a new `BitVec` instance.
-    /// The returned instance has to be freed with `bit_vec_dealloc`.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_bit_vec_new(size: usize) -> *mut BitVec {
-        Box::into_raw(Box::new(BitVec::new(size)))
-    }
-
-    /// Loads a `BitVec` from the provided data.
-    /// The returned instance has to be freed with `bit_vec_dealloc`.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_bit_vec_load(
-        data: *const u8,
-        data_length: usize,
-    ) -> *mut BitVec {
-        let data = std::slice::from_raw_parts(data, data_length);
-        Box::into_raw(Box::new(BitVec::from(data)))
-    }
-
-    /// Clones a `BitVec`.
-    /// The returned instance has to be freed with `bit_vec_dealloc`.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_bit_vec_clone(
-        this: *const BitVec,
-    ) -> *mut BitVec {
-        Box::into_raw(Box::new((*this).clone()))
-    }
-
-    /// Deallocates a `BitVec`.
-    ///
-    /// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_bit_vec_dealloc(this: *mut BitVec) {
-        _ = Box::from_raw(this);
-    }
-
-    /// Gets the value of a bit from the `BitVec`.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_bit_vec_get(
-        this: *const BitVec,
-        index: usize,
-    ) -> bool {
-        (*this).get(index)
-    }
-
-    /// Sets the value of a bit in the `BitVec`.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_bit_vec_set(
-        this: *mut BitVec,
-        index: usize,
-        value: bool,
-    ) -> bool {
-        (*this).set(index, value)
-    }
-
-    /// Sets the value of all bits in the `BitVec`.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_bit_vec_fill(this: *mut BitVec, value: bool) {
-        (*this).fill(value)
-    }
-
-    /// Gets the length of the `BitVec` in bits.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_bit_vec_len(this: *const BitVec) -> usize {
-        (*this).len()
-    }
-
-    /// Returns true if length is 0.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_bit_vec_is_empty(this: *const BitVec) -> bool {
-        (*this).is_empty()
-    }
-
-    /// Gets an unsafe reference to the data of the `BitVec` instance.
-    ///
-    /// ## Safety
-    ///
-    /// The caller has to make sure to never access the returned memory after the `BitVec`
-    /// instance has been consumed or manually deallocated.
-    ///
-    /// Reading and writing concurrently to either the original instance or the returned data will
-    /// result in undefined behavior.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_bit_vec_unsafe_data_ref(
-        this: *mut BitVec,
-    ) -> CByteSlice {
-        let data = (*this).data_ref_mut();
-        CByteSlice {
-            start: data.as_mut_ptr_range().start,
-            length: data.len(),
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use crate::{BitVec, DataRef};
diff --git a/crates/servicepoint/src/byte_grid.rs b/crates/servicepoint/src/byte_grid.rs
index 1fd0328..9a17ead 100644
--- a/crates/servicepoint/src/byte_grid.rs
+++ b/crates/servicepoint/src/byte_grid.rs
@@ -108,119 +108,6 @@ impl From<ByteGrid> for Vec<u8> {
     }
 }
 
-#[cfg(feature = "c_api")]
-pub mod c_api {
-    use crate::data_ref::DataRef;
-    use crate::grid::Grid;
-    use crate::{ByteGrid, CByteSlice};
-
-    /// Creates a new `ByteGrid` instance.
-    /// The returned instance has to be freed with `byte_grid_dealloc`.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_byte_grid_new(
-        width: usize,
-        height: usize,
-    ) -> *mut ByteGrid {
-        Box::into_raw(Box::new(ByteGrid::new(width, height)))
-    }
-
-    /// Loads a `ByteGrid` with the specified dimensions from the provided data.
-    /// The returned instance has to be freed with `byte_grid_dealloc`.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_byte_grid_load(
-        width: usize,
-        height: usize,
-        data: *const u8,
-        data_length: usize,
-    ) -> *mut ByteGrid {
-        let data = std::slice::from_raw_parts(data, data_length);
-        Box::into_raw(Box::new(ByteGrid::load(width, height, data)))
-    }
-
-    /// Clones a `ByteGrid`.
-    /// The returned instance has to be freed with `byte_grid_dealloc`.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_byte_grid_clone(
-        this: *const ByteGrid,
-    ) -> *mut ByteGrid {
-        Box::into_raw(Box::new((*this).clone()))
-    }
-
-    /// Deallocates a `ByteGrid`.
-    ///
-    /// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_byte_grid_dealloc(this: *mut ByteGrid) {
-        _ = Box::from_raw(this);
-    }
-
-    /// Get the current value at the specified position
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_byte_grid_get(
-        this: *const ByteGrid,
-        x: usize,
-        y: usize,
-    ) -> u8 {
-        (*this).get(x, y)
-    }
-
-    /// Sets the current value at the specified position
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_byte_grid_set(
-        this: *mut ByteGrid,
-        x: usize,
-        y: usize,
-        value: u8,
-    ) {
-        (*this).set(x, y, value);
-    }
-
-    /// Fills the whole `ByteGrid` with the specified value
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_byte_grid_fill(
-        this: *mut ByteGrid,
-        value: u8,
-    ) {
-        (*this).fill(value);
-    }
-
-    /// Gets the width in pixels of the `ByteGrid` instance.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_byte_grid_width(
-        this: *const ByteGrid,
-    ) -> usize {
-        (*this).width
-    }
-
-    /// Gets the height in pixels of the `ByteGrid` instance.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_byte_grid_height(
-        this: *const ByteGrid,
-    ) -> usize {
-        (*this).height
-    }
-
-    /// Gets an unsafe reference to the data of the `ByteGrid` instance.
-    ///
-    /// ## Safety
-    ///
-    /// The caller has to make sure to never access the returned memory after the `ByteGrid`
-    /// instance has been consumed or manually deallocated.
-    ///
-    /// Reading and writing concurrently to either the original instance or the returned data will
-    /// result in undefined behavior.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_byte_grid_unsafe_data_ref(
-        this: *mut ByteGrid,
-    ) -> CByteSlice {
-        let data = (*this).data_ref_mut();
-        CByteSlice {
-            start: data.as_mut_ptr_range().start,
-            length: data.len(),
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use crate::{ByteGrid, DataRef, Grid};
diff --git a/crates/servicepoint/src/command.rs b/crates/servicepoint/src/command.rs
index de6a492..4e653eb 100644
--- a/crates/servicepoint/src/command.rs
+++ b/crates/servicepoint/src/command.rs
@@ -391,179 +391,6 @@ impl Command {
     }
 }
 
-#[cfg(feature = "c_api")]
-pub mod c_api {
-    use std::ptr::null_mut;
-
-    use crate::{
-        BitVec, Brightness, ByteGrid, Command, CompressionCode, Offset, Origin,
-        Packet, PixelGrid,
-    };
-
-    /// Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process.
-    ///
-    /// Returns: pointer to command or NULL
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_try_from_packet(
-        packet: *mut Packet,
-    ) -> *mut Command {
-        let packet = *Box::from_raw(packet);
-        match Command::try_from(packet) {
-            Err(_) => null_mut(),
-            Ok(command) => Box::into_raw(Box::new(command)),
-        }
-    }
-
-    /// Clones a `Command` instance
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_clone(
-        original: *const Command,
-    ) -> *mut Command {
-        Box::into_raw(Box::new((*original).clone()))
-    }
-
-    /// Allocates a new `Command::Clear` instance
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_clear() -> *mut Command {
-        Box::into_raw(Box::new(Command::Clear))
-    }
-
-    /// Allocates a new `Command::HardReset` instance
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_hard_reset() -> *mut Command {
-        Box::into_raw(Box::new(Command::HardReset))
-    }
-
-    /// Allocates a new `Command::FadeOut` instance
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_fade_out() -> *mut Command {
-        Box::into_raw(Box::new(Command::FadeOut))
-    }
-
-    /// Allocates a new `Command::Brightness` instance
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_brightness(
-        brightness: Brightness,
-    ) -> *mut Command {
-        Box::into_raw(Box::new(Command::Brightness(brightness)))
-    }
-
-    /// Allocates a new `Command::CharBrightness` instance.
-    /// The passed `ByteGrid` gets deallocated in the process.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_char_brightness(
-        x: usize,
-        y: usize,
-        byte_grid: *mut ByteGrid,
-    ) -> *mut Command {
-        let byte_grid = *Box::from_raw(byte_grid);
-        Box::into_raw(Box::new(Command::CharBrightness(
-            Origin(x, y),
-            byte_grid,
-        )))
-    }
-
-    /// Allocates a new `Command::BitmapLinear` instance.
-    /// The passed `BitVec` gets deallocated in the process.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_bitmap_linear(
-        offset: Offset,
-        bit_vec: *mut BitVec,
-        compression: CompressionCode,
-    ) -> *mut Command {
-        let bit_vec = *Box::from_raw(bit_vec);
-        Box::into_raw(Box::new(Command::BitmapLinear(
-            offset,
-            bit_vec,
-            compression,
-        )))
-    }
-
-    /// Allocates a new `Command::BitmapLinearAnd` instance.
-    /// The passed `BitVec` gets deallocated in the process.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_bitmap_linear_and(
-        offset: Offset,
-        bit_vec: *mut BitVec,
-        compression: CompressionCode,
-    ) -> *mut Command {
-        let bit_vec = *Box::from_raw(bit_vec);
-        Box::into_raw(Box::new(Command::BitmapLinearAnd(
-            offset,
-            bit_vec,
-            compression,
-        )))
-    }
-
-    /// Allocates a new `Command::BitmapLinearOr` instance.
-    /// The passed `BitVec` gets deallocated in the process.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_bitmap_linear_or(
-        offset: Offset,
-        bit_vec: *mut BitVec,
-        compression: CompressionCode,
-    ) -> *mut Command {
-        let bit_vec = *Box::from_raw(bit_vec);
-        Box::into_raw(Box::new(Command::BitmapLinearOr(
-            offset,
-            bit_vec,
-            compression,
-        )))
-    }
-
-    /// Allocates a new `Command::BitmapLinearXor` instance.
-    /// The passed `BitVec` gets deallocated in the process.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_bitmap_linear_xor(
-        offset: Offset,
-        bit_vec: *mut BitVec,
-        compression: CompressionCode,
-    ) -> *mut Command {
-        let bit_vec = *Box::from_raw(bit_vec);
-        Box::into_raw(Box::new(Command::BitmapLinearXor(
-            offset,
-            bit_vec,
-            compression,
-        )))
-    }
-
-    /// Allocates a new `Command::Cp437Data` instance.
-    /// The passed `ByteGrid` gets deallocated in the process.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_cp437_data(
-        x: usize,
-        y: usize,
-        byte_grid: *mut ByteGrid,
-    ) -> *mut Command {
-        let byte_grid = *Box::from_raw(byte_grid);
-        Box::into_raw(Box::new(Command::Cp437Data(Origin(x, y), byte_grid)))
-    }
-
-    /// Allocates a new `Command::BitmapLinearWin` instance.
-    /// The passed `PixelGrid` gets deallocated in the process.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_bitmap_linear_win(
-        x: usize,
-        y: usize,
-        byte_grid: *mut PixelGrid,
-        compression_code: CompressionCode,
-    ) -> *mut Command {
-        let byte_grid = *Box::from_raw(byte_grid);
-        Box::into_raw(Box::new(Command::BitmapLinearWin(
-            Origin(x, y),
-            byte_grid,
-            compression_code,
-        )))
-    }
-
-    /// Deallocates a `Command`. Note that connection_send does this implicitly, so you only need
-    /// to do this if you use the library for parsing commands.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_command_dealloc(ptr: *mut Command) {
-        _ = Box::from_raw(ptr);
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use crate::command::TryFromPacketError;
diff --git a/crates/servicepoint/src/connection.rs b/crates/servicepoint/src/connection.rs
index 099e379..356f97a 100644
--- a/crates/servicepoint/src/connection.rs
+++ b/crates/servicepoint/src/connection.rs
@@ -10,8 +10,6 @@ pub struct Connection {
     socket: UdpSocket,
 }
 
-
-
 impl Connection {
     /// Open a new UDP socket and connect to the provided host.
     ///
@@ -64,7 +62,10 @@ impl Connection {
     ///  connection.send(Command::BitmapLinearWin(servicepoint::Origin(0, 0), pixels, CompressionCode::Uncompressed))
     ///     .expect("send failed");
     /// ```
-    pub fn send(&self, packet: impl Into<Packet>) -> Result<(), std::io::Error> {
+    pub fn send(
+        &self,
+        packet: impl Into<Packet>,
+    ) -> Result<(), std::io::Error> {
         let packet = packet.into();
         debug!("sending {packet:?}");
         let data: Vec<u8> = packet.into();
@@ -72,46 +73,3 @@ impl Connection {
         Ok(())
     }
 }
-
-#[cfg(feature = "c_api")]
-pub mod c_api {
-    use std::ffi::{c_char, CStr};
-    use std::ptr::null_mut;
-
-    use crate::{Connection, Packet};
-
-    /// Creates a new instance of Connection.
-    /// The returned instance has to be deallocated with `connection_dealloc`.
-    ///
-    /// returns: NULL if connection fails or connected instance
-    ///
-    /// Panics: bad string encoding
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_connection_open(
-        host: *const c_char,
-    ) -> *mut Connection {
-        let host = CStr::from_ptr(host).to_str().expect("Bad encoding");
-        let connection = match Connection::open(host) {
-            Err(_) => return null_mut(),
-            Ok(value) => value,
-        };
-
-        Box::into_raw(Box::new(connection))
-    }
-
-    /// Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_connection_send(
-        connection: *const Connection,
-        command_ptr: *mut Packet,
-    ) -> bool {
-        let packet = Box::from_raw(command_ptr);
-        (*connection).send(*packet).is_ok()
-    }
-
-    /// Closes and deallocates a connection instance
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_connection_dealloc(ptr: *mut Connection) {
-        _ = Box::from_raw(ptr);
-    }
-}
diff --git a/crates/servicepoint/src/lib.rs b/crates/servicepoint/src/lib.rs
index a3b5b7a..5b3bcea 100644
--- a/crates/servicepoint/src/lib.rs
+++ b/crates/servicepoint/src/lib.rs
@@ -2,8 +2,6 @@ use std::time::Duration;
 
 pub use crate::bit_vec::BitVec;
 pub use crate::byte_grid::ByteGrid;
-#[cfg(feature = "c_api")]
-pub use crate::c_slice::CByteSlice;
 pub use crate::command::{Brightness, Command, Offset, Origin};
 pub use crate::compression_code::CompressionCode;
 pub use crate::connection::Connection;
@@ -14,7 +12,6 @@ pub use crate::pixel_grid::PixelGrid;
 
 mod bit_vec;
 mod byte_grid;
-mod c_slice;
 mod command;
 mod command_code;
 mod compression;
diff --git a/crates/servicepoint/src/packet.rs b/crates/servicepoint/src/packet.rs
index 11c0c03..d6cb78b 100644
--- a/crates/servicepoint/src/packet.rs
+++ b/crates/servicepoint/src/packet.rs
@@ -58,46 +58,6 @@ impl TryFrom<&[u8]> for Packet {
     }
 }
 
-#[cfg(feature = "c_api")]
-mod c_api {
-    use std::ptr::null_mut;
-
-    use crate::{Command, Packet};
-
-    /// Turns a `Command` into a `Packet`. The command gets deallocated in the process.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_packet_from_command(
-        command: *mut Command,
-    ) -> *mut Packet {
-        let command = *Box::from_raw(command);
-        let packet = command.into();
-        Box::into_raw(Box::new(packet))
-    }
-
-    /// Tries to load a `Packet` from the passed array with the specified length.
-    ///
-    /// returns: NULL in case of an error, pointer to the allocated packet otherwise
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_packet_try_load(
-        data: *const u8,
-        length: usize,
-    ) -> *mut Packet {
-        let data = std::slice::from_raw_parts(data, length);
-        match Packet::try_from(data) {
-            Err(_) => null_mut(),
-            Ok(packet) => Box::into_raw(Box::new(packet)),
-        }
-    }
-
-    /// Deallocates a `Packet`.
-    ///
-    /// Note: do not call this if the instance has been consumed in another way, e.g. by sending it.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_packet_dealloc(this: *mut Packet) {
-        _ = Box::from_raw(this)
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use crate::{Header, Packet};
diff --git a/crates/servicepoint/src/pixel_grid.rs b/crates/servicepoint/src/pixel_grid.rs
index 3c19942..bead3da 100644
--- a/crates/servicepoint/src/pixel_grid.rs
+++ b/crates/servicepoint/src/pixel_grid.rs
@@ -127,118 +127,6 @@ impl From<PixelGrid> for Vec<u8> {
     }
 }
 
-#[cfg(feature = "c_api")]
-pub mod c_api {
-    use crate::c_slice::CByteSlice;
-    use crate::{DataRef, Grid, PixelGrid};
-
-    /// Creates a new `PixelGrid` instance.
-    /// The returned instance has to be freed with `pixel_grid_dealloc`.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_pixel_grid_new(
-        width: usize,
-        height: usize,
-    ) -> *mut PixelGrid {
-        Box::into_raw(Box::new(PixelGrid::new(width, height)))
-    }
-
-    /// Loads a `PixelGrid` with the specified dimensions from the provided data.
-    /// The returned instance has to be freed with `pixel_grid_dealloc`.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_pixel_grid_load(
-        width: usize,
-        height: usize,
-        data: *const u8,
-        data_length: usize,
-    ) -> *mut PixelGrid {
-        let data = std::slice::from_raw_parts(data, data_length);
-        Box::into_raw(Box::new(PixelGrid::load(width, height, data)))
-    }
-
-    /// Clones a `PixelGrid`.
-    /// The returned instance has to be freed with `pixel_grid_dealloc`.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_pixel_grid_clone(
-        this: *const PixelGrid,
-    ) -> *mut PixelGrid {
-        Box::into_raw(Box::new((*this).clone()))
-    }
-
-    /// Deallocates a `PixelGrid`.
-    ///
-    /// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_pixel_grid_dealloc(this: *mut PixelGrid) {
-        _ = Box::from_raw(this);
-    }
-
-    /// Get the current value at the specified position
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_pixel_grid_get(
-        this: *const PixelGrid,
-        x: usize,
-        y: usize,
-    ) -> bool {
-        (*this).get(x, y)
-    }
-
-    /// Sets the current value at the specified position
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_pixel_grid_set(
-        this: *mut PixelGrid,
-        x: usize,
-        y: usize,
-        value: bool,
-    ) {
-        (*this).set(x, y, value);
-    }
-
-    /// Fills the whole `PixelGrid` with the specified value
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_pixel_grid_fill(
-        this: *mut PixelGrid,
-        value: bool,
-    ) {
-        (*this).fill(value);
-    }
-
-    /// Gets the width in pixels of the `PixelGrid` instance.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_pixel_grid_width(
-        this: *const PixelGrid,
-    ) -> usize {
-        (*this).width
-    }
-
-    /// Gets the height in pixels of the `PixelGrid` instance.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_pixel_grid_height(
-        this: *const PixelGrid,
-    ) -> usize {
-        (*this).height
-    }
-
-    /// Gets an unsafe reference to the data of the `PixelGrid` instance.
-    ///
-    /// ## Safety
-    ///
-    /// The caller has to make sure to never access the returned memory after the `PixelGrid`
-    /// instance has been consumed or manually deallocated.
-    ///
-    /// Reading and writing concurrently to either the original instance or the returned data will
-    /// result in undefined behavior.
-    #[no_mangle]
-    pub unsafe extern "C" fn sp2_pixel_grid_unsafe_data_ref(
-        this: *mut PixelGrid,
-    ) -> CByteSlice {
-        let data = (*this).data_ref_mut();
-        CByteSlice {
-            start: data.as_mut_ptr_range().start,
-            length: data.len(),
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use crate::{DataRef, Grid, PixelGrid};
diff --git a/crates/servicepoint_binding_c/Cargo.toml b/crates/servicepoint_binding_c/Cargo.toml
index 9a2cb27..d47ccde 100644
--- a/crates/servicepoint_binding_c/Cargo.toml
+++ b/crates/servicepoint_binding_c/Cargo.toml
@@ -10,5 +10,13 @@ repository = "https://github.com/cccb/servicepoint"
 readme = "../../README.md"
 links = "servicepoint"
 
+[lib]
+crate-type = ["staticlib", "cdylib", "rlib"]
+
 [build-dependencies]
 cbindgen = "0.26.0"
+
+[dependencies.servicepoint]
+version = "0.4.2"
+path = "../servicepoint"
+features = ["all_compressions"]
diff --git a/crates/servicepoint_binding_c/build.rs b/crates/servicepoint_binding_c/build.rs
index f5e4607..10505b0 100644
--- a/crates/servicepoint_binding_c/build.rs
+++ b/crates/servicepoint_binding_c/build.rs
@@ -8,12 +8,11 @@ fn main() {
 
     let config =
         Config::from_file(crate_dir.clone() + "/cbindgen.toml").unwrap();
-    let servicepoint_dir = crate_dir.clone() + "/../servicepoint";
 
     let output_dir = env::var("OUT_DIR").unwrap();
     let header_file = output_dir.clone() + "/servicepoint.h";
 
-    generate_with_config(servicepoint_dir, config)
+    generate_with_config(crate_dir, config)
         .unwrap()
         .write_to_file(&header_file);
     println!("cargo:include={output_dir}");
diff --git a/crates/servicepoint_binding_c/cbindgen.toml b/crates/servicepoint_binding_c/cbindgen.toml
index 42d7d04..1c63d58 100644
--- a/crates/servicepoint_binding_c/cbindgen.toml
+++ b/crates/servicepoint_binding_c/cbindgen.toml
@@ -19,17 +19,18 @@ sort_by = "Name"
 usize_is_size_t = true
 
 [defines]
-"feature = compression_zlib" = "SP2_FEATURE_compression_zlib"
-"feature = compression_bzip2" = "SP2_FEATURE_compression_bzip2"
-"feature = compression_lzma" = "SP2_FEATURE_compression_lzma"
-"feature = compression_zstd" = "SP2_FEATURE_compression_zstd"
+#"feature = compression_zlib" = "SP_FEATURE_compression_zlib"
+#"feature = compression_bzip2" = "SP_FEATURE_compression_bzip2"
+#"feature = compression_lzma" = "SP_FEATURE_compression_lzma"
+#"feature = compression_zstd" = "SP_FEATURE_compression_zstd"
 
 [export]
-prefix = "sp2_"
+prefix = "sp_"
 
 [parse]
-#include = ["servicepoint"]
+parse_deps = true
+include = ["servicepoint"]
+extra_bindings = ["servicepoint"]
 
 [parse.expand]
-features = ["c-api"]
-all_features = true
+#all_features = true
diff --git a/crates/servicepoint_binding_c/src/bit_vec.rs b/crates/servicepoint_binding_c/src/bit_vec.rs
new file mode 100644
index 0000000..dfeb5d4
--- /dev/null
+++ b/crates/servicepoint_binding_c/src/bit_vec.rs
@@ -0,0 +1,94 @@
+pub use servicepoint::BitVec;
+use servicepoint::DataRef;
+
+use crate::c_slice::CByteSlice;
+
+/// Creates a new `BitVec` instance.
+/// The returned instance has to be freed with `bit_vec_dealloc`.
+#[no_mangle]
+pub unsafe extern "C" fn sp_bit_vec_new(size: usize) -> *mut BitVec {
+    Box::into_raw(Box::new(BitVec::new(size)))
+}
+
+/// Loads a `BitVec` from the provided data.
+/// The returned instance has to be freed with `bit_vec_dealloc`.
+#[no_mangle]
+pub unsafe extern "C" fn sp_bit_vec_load(
+    data: *const u8,
+    data_length: usize,
+) -> *mut BitVec {
+    let data = std::slice::from_raw_parts(data, data_length);
+    Box::into_raw(Box::new(BitVec::from(data)))
+}
+
+/// Clones a `BitVec`.
+/// The returned instance has to be freed with `bit_vec_dealloc`.
+#[no_mangle]
+pub unsafe extern "C" fn sp_bit_vec_clone(this: *const BitVec) -> *mut BitVec {
+    Box::into_raw(Box::new((*this).clone()))
+}
+
+/// Deallocates a `BitVec`.
+///
+/// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
+#[no_mangle]
+pub unsafe extern "C" fn sp_bit_vec_dealloc(this: *mut BitVec) {
+    _ = Box::from_raw(this);
+}
+
+/// Gets the value of a bit from the `BitVec`.
+#[no_mangle]
+pub unsafe extern "C" fn sp_bit_vec_get(
+    this: *const BitVec,
+    index: usize,
+) -> bool {
+    (*this).get(index)
+}
+
+/// Sets the value of a bit in the `BitVec`.
+#[no_mangle]
+pub unsafe extern "C" fn sp_bit_vec_set(
+    this: *mut BitVec,
+    index: usize,
+    value: bool,
+) -> bool {
+    (*this).set(index, value)
+}
+
+/// Sets the value of all bits in the `BitVec`.
+#[no_mangle]
+pub unsafe extern "C" fn sp_bit_vec_fill(this: *mut BitVec, value: bool) {
+    (*this).fill(value)
+}
+
+/// Gets the length of the `BitVec` in bits.
+#[no_mangle]
+pub unsafe extern "C" fn sp_bit_vec_len(this: *const BitVec) -> usize {
+    (*this).len()
+}
+
+/// Returns true if length is 0.
+#[no_mangle]
+pub unsafe extern "C" fn sp_bit_vec_is_empty(this: *const BitVec) -> bool {
+    (*this).is_empty()
+}
+
+/// Gets an unsafe reference to the data of the `BitVec` instance.
+///
+/// ## Safety
+///
+/// The caller has to make sure to never access the returned memory after the `BitVec`
+/// instance has been consumed or manually deallocated.
+///
+/// Reading and writing concurrently to either the original instance or the returned data will
+/// result in undefined behavior.
+#[no_mangle]
+pub unsafe extern "C" fn sp_bit_vec_unsafe_data_ref(
+    this: *mut BitVec,
+) -> CByteSlice {
+    let data = (*this).data_ref_mut();
+    CByteSlice {
+        start: data.as_mut_ptr_range().start,
+        length: data.len(),
+    }
+}
diff --git a/crates/servicepoint_binding_c/src/byte_grid.rs b/crates/servicepoint_binding_c/src/byte_grid.rs
new file mode 100644
index 0000000..124420f
--- /dev/null
+++ b/crates/servicepoint_binding_c/src/byte_grid.rs
@@ -0,0 +1,103 @@
+pub use servicepoint::ByteGrid;
+use servicepoint::{DataRef, Grid};
+
+use crate::c_slice::CByteSlice;
+
+/// Creates a new `ByteGrid` instance.
+/// The returned instance has to be freed with `byte_grid_dealloc`.
+#[no_mangle]
+pub unsafe extern "C" fn sp_byte_grid_new(
+    width: usize,
+    height: usize,
+) -> *mut ByteGrid {
+    Box::into_raw(Box::new(ByteGrid::new(width, height)))
+}
+
+/// Loads a `ByteGrid` with the specified dimensions from the provided data.
+/// The returned instance has to be freed with `byte_grid_dealloc`.
+#[no_mangle]
+pub unsafe extern "C" fn sp_byte_grid_load(
+    width: usize,
+    height: usize,
+    data: *const u8,
+    data_length: usize,
+) -> *mut ByteGrid {
+    let data = std::slice::from_raw_parts(data, data_length);
+    Box::into_raw(Box::new(ByteGrid::load(width, height, data)))
+}
+
+/// Clones a `ByteGrid`.
+/// The returned instance has to be freed with `byte_grid_dealloc`.
+#[no_mangle]
+pub unsafe extern "C" fn sp_byte_grid_clone(
+    this: *const ByteGrid,
+) -> *mut ByteGrid {
+    Box::into_raw(Box::new((*this).clone()))
+}
+
+/// Deallocates a `ByteGrid`.
+///
+/// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
+#[no_mangle]
+pub unsafe extern "C" fn sp_byte_grid_dealloc(this: *mut ByteGrid) {
+    _ = Box::from_raw(this);
+}
+
+/// Get the current value at the specified position
+#[no_mangle]
+pub unsafe extern "C" fn sp_byte_grid_get(
+    this: *const ByteGrid,
+    x: usize,
+    y: usize,
+) -> u8 {
+    (*this).get(x, y)
+}
+
+/// Sets the current value at the specified position
+#[no_mangle]
+pub unsafe extern "C" fn sp_byte_grid_set(
+    this: *mut ByteGrid,
+    x: usize,
+    y: usize,
+    value: u8,
+) {
+    (*this).set(x, y, value);
+}
+
+/// Fills the whole `ByteGrid` with the specified value
+#[no_mangle]
+pub unsafe extern "C" fn sp_byte_grid_fill(this: *mut ByteGrid, value: u8) {
+    (*this).fill(value);
+}
+
+/// Gets the width in pixels of the `ByteGrid` instance.
+#[no_mangle]
+pub unsafe extern "C" fn sp_byte_grid_width(this: *const ByteGrid) -> usize {
+    (*this).width()
+}
+
+/// Gets the height in pixels of the `ByteGrid` instance.
+#[no_mangle]
+pub unsafe extern "C" fn sp_byte_grid_height(this: *const ByteGrid) -> usize {
+    (*this).height()
+}
+
+/// Gets an unsafe reference to the data of the `ByteGrid` instance.
+///
+/// ## Safety
+///
+/// The caller has to make sure to never access the returned memory after the `ByteGrid`
+/// instance has been consumed or manually deallocated.
+///
+/// Reading and writing concurrently to either the original instance or the returned data will
+/// result in undefined behavior.
+#[no_mangle]
+pub unsafe extern "C" fn sp_byte_grid_unsafe_data_ref(
+    this: *mut ByteGrid,
+) -> CByteSlice {
+    let data = (*this).data_ref_mut();
+    CByteSlice {
+        start: data.as_mut_ptr_range().start,
+        length: data.len(),
+    }
+}
diff --git a/crates/servicepoint/src/c_slice.rs b/crates/servicepoint_binding_c/src/c_slice.rs
similarity index 91%
rename from crates/servicepoint/src/c_slice.rs
rename to crates/servicepoint_binding_c/src/c_slice.rs
index 5ee71f6..9609906 100644
--- a/crates/servicepoint/src/c_slice.rs
+++ b/crates/servicepoint_binding_c/src/c_slice.rs
@@ -1,4 +1,3 @@
-#[cfg(feature = "c_api")]
 #[repr(C)]
 /// Represents a span of memory (`&mut [u8]` ) as a struct usable by C code.
 ///
diff --git a/crates/servicepoint_binding_c/src/command.rs b/crates/servicepoint_binding_c/src/command.rs
new file mode 100644
index 0000000..2d4e7a1
--- /dev/null
+++ b/crates/servicepoint_binding_c/src/command.rs
@@ -0,0 +1,166 @@
+use std::ptr::null_mut;
+
+use servicepoint::{
+    BitVec, ByteGrid, CompressionCode, Origin, Packet, PixelGrid,
+};
+pub use servicepoint::{Brightness, Command, Offset};
+
+/// Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process.
+///
+/// Returns: pointer to command or NULL
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_try_from_packet(
+    packet: *mut Packet,
+) -> *mut Command {
+    let packet = *Box::from_raw(packet);
+    match Command::try_from(packet) {
+        Err(_) => null_mut(),
+        Ok(command) => Box::into_raw(Box::new(command)),
+    }
+}
+
+/// Clones a `Command` instance
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_clone(
+    original: *const Command,
+) -> *mut Command {
+    Box::into_raw(Box::new((*original).clone()))
+}
+
+/// Allocates a new `Command::Clear` instance
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_clear() -> *mut Command {
+    Box::into_raw(Box::new(Command::Clear))
+}
+
+/// Allocates a new `Command::HardReset` instance
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_hard_reset() -> *mut Command {
+    Box::into_raw(Box::new(Command::HardReset))
+}
+
+/// Allocates a new `Command::FadeOut` instance
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_fade_out() -> *mut Command {
+    Box::into_raw(Box::new(Command::FadeOut))
+}
+
+/// Allocates a new `Command::Brightness` instance
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_brightness(
+    brightness: Brightness,
+) -> *mut Command {
+    Box::into_raw(Box::new(Command::Brightness(brightness)))
+}
+
+/// Allocates a new `Command::CharBrightness` instance.
+/// The passed `ByteGrid` gets deallocated in the process.
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_char_brightness(
+    x: usize,
+    y: usize,
+    byte_grid: *mut ByteGrid,
+) -> *mut Command {
+    let byte_grid = *Box::from_raw(byte_grid);
+    Box::into_raw(Box::new(Command::CharBrightness(Origin(x, y), byte_grid)))
+}
+
+/// Allocates a new `Command::BitmapLinear` instance.
+/// The passed `BitVec` gets deallocated in the process.
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_bitmap_linear(
+    offset: Offset,
+    bit_vec: *mut BitVec,
+    compression: CompressionCode,
+) -> *mut Command {
+    let bit_vec = *Box::from_raw(bit_vec);
+    Box::into_raw(Box::new(Command::BitmapLinear(
+        offset,
+        bit_vec,
+        compression,
+    )))
+}
+
+/// Allocates a new `Command::BitmapLinearAnd` instance.
+/// The passed `BitVec` gets deallocated in the process.
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_bitmap_linear_and(
+    offset: Offset,
+    bit_vec: *mut BitVec,
+    compression: CompressionCode,
+) -> *mut Command {
+    let bit_vec = *Box::from_raw(bit_vec);
+    Box::into_raw(Box::new(Command::BitmapLinearAnd(
+        offset,
+        bit_vec,
+        compression,
+    )))
+}
+
+/// Allocates a new `Command::BitmapLinearOr` instance.
+/// The passed `BitVec` gets deallocated in the process.
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_bitmap_linear_or(
+    offset: Offset,
+    bit_vec: *mut BitVec,
+    compression: CompressionCode,
+) -> *mut Command {
+    let bit_vec = *Box::from_raw(bit_vec);
+    Box::into_raw(Box::new(Command::BitmapLinearOr(
+        offset,
+        bit_vec,
+        compression,
+    )))
+}
+
+/// Allocates a new `Command::BitmapLinearXor` instance.
+/// The passed `BitVec` gets deallocated in the process.
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_bitmap_linear_xor(
+    offset: Offset,
+    bit_vec: *mut BitVec,
+    compression: CompressionCode,
+) -> *mut Command {
+    let bit_vec = *Box::from_raw(bit_vec);
+    Box::into_raw(Box::new(Command::BitmapLinearXor(
+        offset,
+        bit_vec,
+        compression,
+    )))
+}
+
+/// Allocates a new `Command::Cp437Data` instance.
+/// The passed `ByteGrid` gets deallocated in the process.
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_cp437_data(
+    x: usize,
+    y: usize,
+    byte_grid: *mut ByteGrid,
+) -> *mut Command {
+    let byte_grid = *Box::from_raw(byte_grid);
+    Box::into_raw(Box::new(Command::Cp437Data(Origin(x, y), byte_grid)))
+}
+
+/// Allocates a new `Command::BitmapLinearWin` instance.
+/// The passed `PixelGrid` gets deallocated in the process.
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_bitmap_linear_win(
+    x: usize,
+    y: usize,
+    byte_grid: *mut PixelGrid,
+    compression_code: CompressionCode,
+) -> *mut Command {
+    let byte_grid = *Box::from_raw(byte_grid);
+    Box::into_raw(Box::new(Command::BitmapLinearWin(
+        Origin(x, y),
+        byte_grid,
+        compression_code,
+    )))
+}
+
+/// Deallocates a `Command`. Note that connection_send does this implicitly, so you only need
+/// to do this if you use the library for parsing commands.
+#[no_mangle]
+pub unsafe extern "C" fn sp_command_dealloc(ptr: *mut Command) {
+    _ = Box::from_raw(ptr);
+}
diff --git a/crates/servicepoint_binding_c/src/connection.rs b/crates/servicepoint_binding_c/src/connection.rs
new file mode 100644
index 0000000..b1ea334
--- /dev/null
+++ b/crates/servicepoint_binding_c/src/connection.rs
@@ -0,0 +1,40 @@
+use std::ffi::{c_char, CStr};
+use std::ptr::null_mut;
+
+pub use servicepoint::Connection;
+use servicepoint::Packet;
+
+/// Creates a new instance of Connection.
+/// The returned instance has to be deallocated with `connection_dealloc`.
+///
+/// returns: NULL if connection fails or connected instance
+///
+/// Panics: bad string encoding
+#[no_mangle]
+pub unsafe extern "C" fn sp_connection_open(
+    host: *const c_char,
+) -> *mut Connection {
+    let host = CStr::from_ptr(host).to_str().expect("Bad encoding");
+    let connection = match Connection::open(host) {
+        Err(_) => return null_mut(),
+        Ok(value) => value,
+    };
+
+    Box::into_raw(Box::new(connection))
+}
+
+/// Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.
+#[no_mangle]
+pub unsafe extern "C" fn sp_connection_send(
+    connection: *const Connection,
+    command_ptr: *mut Packet,
+) -> bool {
+    let packet = Box::from_raw(command_ptr);
+    (*connection).send(*packet).is_ok()
+}
+
+/// Closes and deallocates a connection instance
+#[no_mangle]
+pub unsafe extern "C" fn sp_connection_dealloc(ptr: *mut Connection) {
+    _ = Box::from_raw(ptr);
+}
diff --git a/crates/servicepoint_binding_c/src/lib.rs b/crates/servicepoint_binding_c/src/lib.rs
index e69de29..4ecbd5d 100644
--- a/crates/servicepoint_binding_c/src/lib.rs
+++ b/crates/servicepoint_binding_c/src/lib.rs
@@ -0,0 +1,14 @@
+pub use servicepoint::{
+    CompressionCode, PIXEL_COUNT, PIXEL_HEIGHT, PIXEL_WIDTH, TILE_HEIGHT,
+    TILE_SIZE, TILE_WIDTH,
+};
+
+pub mod bit_vec;
+pub mod byte_grid;
+pub mod c_slice;
+pub mod command;
+pub mod connection;
+pub mod packet;
+pub mod pixel_grid;
+
+pub const FRAME_PACING_MS: u32 = servicepoint::FRAME_PACING.as_millis() as u32;
diff --git a/crates/servicepoint_binding_c/src/packet.rs b/crates/servicepoint_binding_c/src/packet.rs
new file mode 100644
index 0000000..9e90f3f
--- /dev/null
+++ b/crates/servicepoint_binding_c/src/packet.rs
@@ -0,0 +1,37 @@
+use std::ptr::null_mut;
+
+use servicepoint::Command;
+pub use servicepoint::Packet;
+
+/// Turns a `Command` into a `Packet`. The command gets deallocated in the process.
+#[no_mangle]
+pub unsafe extern "C" fn sp_packet_from_command(
+    command: *mut Command,
+) -> *mut Packet {
+    let command = *Box::from_raw(command);
+    let packet = command.into();
+    Box::into_raw(Box::new(packet))
+}
+
+/// Tries to load a `Packet` from the passed array with the specified length.
+///
+/// returns: NULL in case of an error, pointer to the allocated packet otherwise
+#[no_mangle]
+pub unsafe extern "C" fn sp_packet_try_load(
+    data: *const u8,
+    length: usize,
+) -> *mut Packet {
+    let data = std::slice::from_raw_parts(data, length);
+    match Packet::try_from(data) {
+        Err(_) => null_mut(),
+        Ok(packet) => Box::into_raw(Box::new(packet)),
+    }
+}
+
+/// Deallocates a `Packet`.
+///
+/// Note: do not call this if the instance has been consumed in another way, e.g. by sending it.
+#[no_mangle]
+pub unsafe extern "C" fn sp_packet_dealloc(this: *mut Packet) {
+    _ = Box::from_raw(this)
+}
diff --git a/crates/servicepoint_binding_c/src/pixel_grid.rs b/crates/servicepoint_binding_c/src/pixel_grid.rs
new file mode 100644
index 0000000..87090d9
--- /dev/null
+++ b/crates/servicepoint_binding_c/src/pixel_grid.rs
@@ -0,0 +1,102 @@
+use servicepoint::{DataRef, Grid, PixelGrid};
+
+use crate::c_slice::CByteSlice;
+
+/// Creates a new `PixelGrid` instance.
+/// The returned instance has to be freed with `pixel_grid_dealloc`.
+#[no_mangle]
+pub unsafe extern "C" fn sp_pixel_grid_new(
+    width: usize,
+    height: usize,
+) -> *mut PixelGrid {
+    Box::into_raw(Box::new(PixelGrid::new(width, height)))
+}
+
+/// Loads a `PixelGrid` with the specified dimensions from the provided data.
+/// The returned instance has to be freed with `pixel_grid_dealloc`.
+#[no_mangle]
+pub unsafe extern "C" fn sp_pixel_grid_load(
+    width: usize,
+    height: usize,
+    data: *const u8,
+    data_length: usize,
+) -> *mut PixelGrid {
+    let data = std::slice::from_raw_parts(data, data_length);
+    Box::into_raw(Box::new(PixelGrid::load(width, height, data)))
+}
+
+/// Clones a `PixelGrid`.
+/// The returned instance has to be freed with `pixel_grid_dealloc`.
+#[no_mangle]
+pub unsafe extern "C" fn sp_pixel_grid_clone(
+    this: *const PixelGrid,
+) -> *mut PixelGrid {
+    Box::into_raw(Box::new((*this).clone()))
+}
+
+/// Deallocates a `PixelGrid`.
+///
+/// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
+#[no_mangle]
+pub unsafe extern "C" fn sp_pixel_grid_dealloc(this: *mut PixelGrid) {
+    _ = Box::from_raw(this);
+}
+
+/// Get the current value at the specified position
+#[no_mangle]
+pub unsafe extern "C" fn sp_pixel_grid_get(
+    this: *const PixelGrid,
+    x: usize,
+    y: usize,
+) -> bool {
+    (*this).get(x, y)
+}
+
+/// Sets the current value at the specified position
+#[no_mangle]
+pub unsafe extern "C" fn sp_pixel_grid_set(
+    this: *mut PixelGrid,
+    x: usize,
+    y: usize,
+    value: bool,
+) {
+    (*this).set(x, y, value);
+}
+
+/// Fills the whole `PixelGrid` with the specified value
+#[no_mangle]
+pub unsafe extern "C" fn sp_pixel_grid_fill(this: *mut PixelGrid, value: bool) {
+    (*this).fill(value);
+}
+
+/// Gets the width in pixels of the `PixelGrid` instance.
+#[no_mangle]
+pub unsafe extern "C" fn sp_pixel_grid_width(this: *const PixelGrid) -> usize {
+    (*this).width()
+}
+
+/// Gets the height in pixels of the `PixelGrid` instance.
+#[no_mangle]
+pub unsafe extern "C" fn sp_pixel_grid_height(this: *const PixelGrid) -> usize {
+    (*this).height()
+}
+
+/// Gets an unsafe reference to the data of the `PixelGrid` instance.
+///
+/// ## Safety
+///
+/// The caller has to make sure to never access the returned memory after the `PixelGrid`
+/// instance has been consumed or manually deallocated.
+///
+/// Reading and writing concurrently to either the original instance or the returned data will
+/// result in undefined behavior.
+#[no_mangle]
+pub unsafe extern "C" fn sp_pixel_grid_unsafe_data_ref(
+    this: *mut PixelGrid,
+) -> CByteSlice {
+    let data = (*this).data_ref_mut();
+    CByteSlice {
+        start: data.as_mut_ptr_range().start,
+        length: data.len(),
+    }
+}
diff --git a/crates/servicepoint_binding_cs/Cargo.toml b/crates/servicepoint_binding_cs/Cargo.toml
index ed651f5..cfc909c 100644
--- a/crates/servicepoint_binding_cs/Cargo.toml
+++ b/crates/servicepoint_binding_cs/Cargo.toml
@@ -8,8 +8,8 @@ readme = "../../README.md"
 [lib]
 crate-type = ["cdylib"]
 
-[dependencies]
-servicepoint = { path = "../servicepoint", features = ["c_api"] }
-
 [build-dependencies]
 csbindgen = "1.8.0"
+
+[dependencies]
+servicepoint_binding_c = { path = "../servicepoint_binding_c" }
diff --git a/crates/servicepoint_binding_cs/ServicePoint.sln b/crates/servicepoint_binding_cs/ServicePoint.sln
index c505f07..29b9889 100644
--- a/crates/servicepoint_binding_cs/ServicePoint.sln
+++ b/crates/servicepoint_binding_cs/ServicePoint.sln
@@ -1,8 +1,8 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint", "src/ServicePoint.csproj", "{70EFFA3F-012A-4518-9627-466BEAE4252E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint", "ServicePoint/ServicePoint.csproj", "{70EFFA3F-012A-4518-9627-466BEAE4252E}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lang-cs", "../examples/lang_cs/lang_cs.csproj", "{DA3B8B6E-993A-47DA-844B-F92AF520FF59}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lang-cs", "../../examples/lang_cs/lang_cs.csproj", "{DA3B8B6E-993A-47DA-844B-F92AF520FF59}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/crates/servicepoint_binding_cs/src/BindGen/ServicePoint.g.cs b/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs
similarity index 52%
rename from crates/servicepoint_binding_cs/src/BindGen/ServicePoint.g.cs
rename to crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs
index d138126..fd8f466 100644
--- a/crates/servicepoint_binding_cs/src/BindGen/ServicePoint.g.cs
+++ b/crates/servicepoint_binding_cs/ServicePoint/BindGen/ServicePoint.g.cs
@@ -12,218 +12,228 @@ namespace ServicePoint.BindGen
 {
     public static unsafe partial class NativeMethods
     {
-        const string __DllName = "servicepoint";
+        const string __DllName = "servicepoint_binding_c";
 
+        public const nuint TILE_SIZE = 8;
+        public const nuint TILE_WIDTH = 56;
+        public const nuint TILE_HEIGHT = 20;
 
 
         /// <summary>Creates a new `BitVec` instance. The returned instance has to be freed with `bit_vec_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern BitVec* sp2_bit_vec_new(nuint size);
+        [DllImport(__DllName, EntryPoint = "sp_bit_vec_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern BitVec* sp_bit_vec_new(nuint size);
 
         /// <summary>Loads a `BitVec` from the provided data. The returned instance has to be freed with `bit_vec_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern BitVec* sp2_bit_vec_load(byte* data, nuint data_length);
+        [DllImport(__DllName, EntryPoint = "sp_bit_vec_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern BitVec* sp_bit_vec_load(byte* data, nuint data_length);
 
         /// <summary>Clones a `BitVec`. The returned instance has to be freed with `bit_vec_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern BitVec* sp2_bit_vec_clone(BitVec* @this);
+        [DllImport(__DllName, EntryPoint = "sp_bit_vec_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern BitVec* sp_bit_vec_clone(BitVec* @this);
 
         /// <summary>Deallocates a `BitVec`.  Note: do not call this if the grid has been consumed in another way, e.g. to create a command.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_bit_vec_dealloc(BitVec* @this);
+        [DllImport(__DllName, EntryPoint = "sp_bit_vec_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp_bit_vec_dealloc(BitVec* @this);
 
         /// <summary>Gets the value of a bit from the `BitVec`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        [DllImport(__DllName, EntryPoint = "sp_bit_vec_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
         [return: MarshalAs(UnmanagedType.U1)]
-        public static extern bool sp2_bit_vec_get(BitVec* @this, nuint index);
+        public static extern bool sp_bit_vec_get(BitVec* @this, nuint index);
 
         /// <summary>Sets the value of a bit in the `BitVec`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        [DllImport(__DllName, EntryPoint = "sp_bit_vec_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
         [return: MarshalAs(UnmanagedType.U1)]
-        public static extern bool sp2_bit_vec_set(BitVec* @this, nuint index, [MarshalAs(UnmanagedType.U1)] bool value);
+        public static extern bool sp_bit_vec_set(BitVec* @this, nuint index, [MarshalAs(UnmanagedType.U1)] bool value);
 
         /// <summary>Sets the value of all bits in the `BitVec`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_bit_vec_fill(BitVec* @this, [MarshalAs(UnmanagedType.U1)] bool value);
+        [DllImport(__DllName, EntryPoint = "sp_bit_vec_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp_bit_vec_fill(BitVec* @this, [MarshalAs(UnmanagedType.U1)] bool value);
 
         /// <summary>Gets the length of the `BitVec` in bits.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern nuint sp2_bit_vec_len(BitVec* @this);
+        [DllImport(__DllName, EntryPoint = "sp_bit_vec_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern nuint sp_bit_vec_len(BitVec* @this);
 
         /// <summary>Returns true if length is 0.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_is_empty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        [DllImport(__DllName, EntryPoint = "sp_bit_vec_is_empty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
         [return: MarshalAs(UnmanagedType.U1)]
-        public static extern bool sp2_bit_vec_is_empty(BitVec* @this);
+        public static extern bool sp_bit_vec_is_empty(BitVec* @this);
 
         /// <summary>Gets an unsafe reference to the data of the `BitVec` instance.  ## Safety  The caller has to make sure to never access the returned memory after the `BitVec` instance has been consumed or manually deallocated.  Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_bit_vec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern CByteSlice sp2_bit_vec_unsafe_data_ref(BitVec* @this);
+        [DllImport(__DllName, EntryPoint = "sp_bit_vec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern CByteSlice sp_bit_vec_unsafe_data_ref(BitVec* @this);
 
         /// <summary>Creates a new `ByteGrid` instance. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern ByteGrid* sp2_byte_grid_new(nuint width, nuint height);
+        [DllImport(__DllName, EntryPoint = "sp_byte_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern ByteGrid* sp_byte_grid_new(nuint width, nuint height);
 
         /// <summary>Loads a `ByteGrid` with the specified dimensions from the provided data. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern ByteGrid* sp2_byte_grid_load(nuint width, nuint height, byte* data, nuint data_length);
+        [DllImport(__DllName, EntryPoint = "sp_byte_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern ByteGrid* sp_byte_grid_load(nuint width, nuint height, byte* data, nuint data_length);
 
         /// <summary>Clones a `ByteGrid`. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern ByteGrid* sp2_byte_grid_clone(ByteGrid* @this);
+        [DllImport(__DllName, EntryPoint = "sp_byte_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern ByteGrid* sp_byte_grid_clone(ByteGrid* @this);
 
         /// <summary>Deallocates a `ByteGrid`.  Note: do not call this if the grid has been consumed in another way, e.g. to create a command.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_byte_grid_dealloc(ByteGrid* @this);
+        [DllImport(__DllName, EntryPoint = "sp_byte_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp_byte_grid_dealloc(ByteGrid* @this);
 
         /// <summary>Get the current value at the specified position</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern byte sp2_byte_grid_get(ByteGrid* @this, nuint x, nuint y);
+        [DllImport(__DllName, EntryPoint = "sp_byte_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern byte sp_byte_grid_get(ByteGrid* @this, nuint x, nuint y);
 
         /// <summary>Sets the current value at the specified position</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_byte_grid_set(ByteGrid* @this, nuint x, nuint y, byte value);
+        [DllImport(__DllName, EntryPoint = "sp_byte_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp_byte_grid_set(ByteGrid* @this, nuint x, nuint y, byte value);
 
         /// <summary>Fills the whole `ByteGrid` with the specified value</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_byte_grid_fill(ByteGrid* @this, byte value);
+        [DllImport(__DllName, EntryPoint = "sp_byte_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp_byte_grid_fill(ByteGrid* @this, byte value);
 
         /// <summary>Gets the width in pixels of the `ByteGrid` instance.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern nuint sp2_byte_grid_width(ByteGrid* @this);
+        [DllImport(__DllName, EntryPoint = "sp_byte_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern nuint sp_byte_grid_width(ByteGrid* @this);
 
         /// <summary>Gets the height in pixels of the `ByteGrid` instance.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern nuint sp2_byte_grid_height(ByteGrid* @this);
+        [DllImport(__DllName, EntryPoint = "sp_byte_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern nuint sp_byte_grid_height(ByteGrid* @this);
 
         /// <summary>Gets an unsafe reference to the data of the `ByteGrid` instance.  ## Safety  The caller has to make sure to never access the returned memory after the `ByteGrid` instance has been consumed or manually deallocated.  Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_byte_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern CByteSlice sp2_byte_grid_unsafe_data_ref(ByteGrid* @this);
+        [DllImport(__DllName, EntryPoint = "sp_byte_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern CByteSlice sp_byte_grid_unsafe_data_ref(ByteGrid* @this);
 
         /// <summary>Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process.  Returns: pointer to command or NULL</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_try_from_packet(Packet* packet);
+        [DllImport(__DllName, EntryPoint = "sp_command_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_try_from_packet(Packet* packet);
 
         /// <summary>Clones a `Command` instance</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_clone(Command* original);
+        [DllImport(__DllName, EntryPoint = "sp_command_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_clone(Command* original);
 
         /// <summary>Allocates a new `Command::Clear` instance</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_clear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_clear();
+        [DllImport(__DllName, EntryPoint = "sp_command_clear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_clear();
 
         /// <summary>Allocates a new `Command::HardReset` instance</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_hard_reset", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_hard_reset();
+        [DllImport(__DllName, EntryPoint = "sp_command_hard_reset", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_hard_reset();
 
         /// <summary>Allocates a new `Command::FadeOut` instance</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_fade_out", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_fade_out();
+        [DllImport(__DllName, EntryPoint = "sp_command_fade_out", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_fade_out();
 
         /// <summary>Allocates a new `Command::Brightness` instance</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_brightness(byte brightness);
+        [DllImport(__DllName, EntryPoint = "sp_command_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_brightness(byte brightness);
 
         /// <summary>Allocates a new `Command::CharBrightness` instance. The passed `ByteGrid` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_char_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_char_brightness(nuint x, nuint y, ByteGrid* byte_grid);
+        [DllImport(__DllName, EntryPoint = "sp_command_char_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_char_brightness(nuint x, nuint y, ByteGrid* byte_grid);
 
         /// <summary>Allocates a new `Command::BitmapLinear` instance. The passed `BitVec` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_bitmap_linear(nuint offset, BitVec* bit_vec, CompressionCode compression);
+        [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_bitmap_linear(nuint offset, BitVec* bit_vec, CompressionCode compression);
 
         /// <summary>Allocates a new `Command::BitmapLinearAnd` instance. The passed `BitVec` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_and", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_bitmap_linear_and(nuint offset, BitVec* bit_vec, CompressionCode compression);
+        [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_and", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_bitmap_linear_and(nuint offset, BitVec* bit_vec, CompressionCode compression);
 
         /// <summary>Allocates a new `Command::BitmapLinearOr` instance. The passed `BitVec` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_or", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_bitmap_linear_or(nuint offset, BitVec* bit_vec, CompressionCode compression);
+        [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_or", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_bitmap_linear_or(nuint offset, BitVec* bit_vec, CompressionCode compression);
 
         /// <summary>Allocates a new `Command::BitmapLinearXor` instance. The passed `BitVec` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_xor", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_bitmap_linear_xor(nuint offset, BitVec* bit_vec, CompressionCode compression);
+        [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_xor", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_bitmap_linear_xor(nuint offset, BitVec* bit_vec, CompressionCode compression);
 
         /// <summary>Allocates a new `Command::Cp437Data` instance. The passed `ByteGrid` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_cp437_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_cp437_data(nuint x, nuint y, ByteGrid* byte_grid);
+        [DllImport(__DllName, EntryPoint = "sp_command_cp437_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_cp437_data(nuint x, nuint y, ByteGrid* byte_grid);
 
         /// <summary>Allocates a new `Command::BitmapLinearWin` instance. The passed `PixelGrid` gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_win", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Command* sp2_command_bitmap_linear_win(nuint x, nuint y, PixelGrid* byte_grid, CompressionCode compression_code);
+        [DllImport(__DllName, EntryPoint = "sp_command_bitmap_linear_win", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Command* sp_command_bitmap_linear_win(nuint x, nuint y, PixelGrid* byte_grid, CompressionCode compression_code);
 
         /// <summary>Deallocates a `Command`. Note that connection_send does this implicitly, so you only need to do this if you use the library for parsing commands.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_command_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_command_dealloc(Command* ptr);
+        [DllImport(__DllName, EntryPoint = "sp_command_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp_command_dealloc(Command* ptr);
 
         /// <summary>Creates a new instance of Connection. The returned instance has to be deallocated with `connection_dealloc`.  returns: NULL if connection fails or connected instance  Panics: bad string encoding</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_connection_open", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Connection* sp2_connection_open(byte* host);
+        [DllImport(__DllName, EntryPoint = "sp_connection_open", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Connection* sp_connection_open(byte* host);
 
         /// <summary>Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_connection_send", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        [DllImport(__DllName, EntryPoint = "sp_connection_send", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
         [return: MarshalAs(UnmanagedType.U1)]
-        public static extern bool sp2_connection_send(Connection* connection, Packet* command_ptr);
+        public static extern bool sp_connection_send(Connection* connection, Packet* command_ptr);
 
         /// <summary>Closes and deallocates a connection instance</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_connection_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_connection_dealloc(Connection* ptr);
+        [DllImport(__DllName, EntryPoint = "sp_connection_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp_connection_dealloc(Connection* ptr);
 
         /// <summary>Creates a new `PixelGrid` instance. The returned instance has to be freed with `pixel_grid_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern PixelGrid* sp2_pixel_grid_new(nuint width, nuint height);
+        [DllImport(__DllName, EntryPoint = "sp_pixel_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern PixelGrid* sp_pixel_grid_new(nuint width, nuint height);
 
         /// <summary>Loads a `PixelGrid` with the specified dimensions from the provided data. The returned instance has to be freed with `pixel_grid_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern PixelGrid* sp2_pixel_grid_load(nuint width, nuint height, byte* data, nuint data_length);
+        [DllImport(__DllName, EntryPoint = "sp_pixel_grid_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern PixelGrid* sp_pixel_grid_load(nuint width, nuint height, byte* data, nuint data_length);
 
         /// <summary>Clones a `PixelGrid`. The returned instance has to be freed with `pixel_grid_dealloc`.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern PixelGrid* sp2_pixel_grid_clone(PixelGrid* @this);
+        [DllImport(__DllName, EntryPoint = "sp_pixel_grid_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern PixelGrid* sp_pixel_grid_clone(PixelGrid* @this);
 
         /// <summary>Deallocates a `PixelGrid`.  Note: do not call this if the grid has been consumed in another way, e.g. to create a command.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_pixel_grid_dealloc(PixelGrid* @this);
+        [DllImport(__DllName, EntryPoint = "sp_pixel_grid_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp_pixel_grid_dealloc(PixelGrid* @this);
 
         /// <summary>Get the current value at the specified position</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        [DllImport(__DllName, EntryPoint = "sp_pixel_grid_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
         [return: MarshalAs(UnmanagedType.U1)]
-        public static extern bool sp2_pixel_grid_get(PixelGrid* @this, nuint x, nuint y);
+        public static extern bool sp_pixel_grid_get(PixelGrid* @this, nuint x, nuint y);
 
         /// <summary>Sets the current value at the specified position</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_pixel_grid_set(PixelGrid* @this, nuint x, nuint y, [MarshalAs(UnmanagedType.U1)] bool value);
+        [DllImport(__DllName, EntryPoint = "sp_pixel_grid_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp_pixel_grid_set(PixelGrid* @this, nuint x, nuint y, [MarshalAs(UnmanagedType.U1)] bool value);
 
         /// <summary>Fills the whole `PixelGrid` with the specified value</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_pixel_grid_fill(PixelGrid* @this, [MarshalAs(UnmanagedType.U1)] bool value);
+        [DllImport(__DllName, EntryPoint = "sp_pixel_grid_fill", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp_pixel_grid_fill(PixelGrid* @this, [MarshalAs(UnmanagedType.U1)] bool value);
 
         /// <summary>Gets the width in pixels of the `PixelGrid` instance.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern nuint sp2_pixel_grid_width(PixelGrid* @this);
+        [DllImport(__DllName, EntryPoint = "sp_pixel_grid_width", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern nuint sp_pixel_grid_width(PixelGrid* @this);
 
         /// <summary>Gets the height in pixels of the `PixelGrid` instance.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern nuint sp2_pixel_grid_height(PixelGrid* @this);
+        [DllImport(__DllName, EntryPoint = "sp_pixel_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern nuint sp_pixel_grid_height(PixelGrid* @this);
 
         /// <summary>Gets an unsafe reference to the data of the `PixelGrid` instance.  ## Safety  The caller has to make sure to never access the returned memory after the `PixelGrid` instance has been consumed or manually deallocated.  Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_pixel_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern CByteSlice sp2_pixel_grid_unsafe_data_ref(PixelGrid* @this);
+        [DllImport(__DllName, EntryPoint = "sp_pixel_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern CByteSlice sp_pixel_grid_unsafe_data_ref(PixelGrid* @this);
 
         /// <summary>Turns a `Command` into a `Packet`. The command gets deallocated in the process.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_packet_from_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Packet* sp2_packet_from_command(Command* command);
+        [DllImport(__DllName, EntryPoint = "sp_packet_from_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Packet* sp_packet_from_command(Command* command);
 
         /// <summary>Tries to load a `Packet` from the passed array with the specified length.  returns: NULL in case of an error, pointer to the allocated packet otherwise</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_packet_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern Packet* sp2_packet_try_load(byte* data, nuint length);
+        [DllImport(__DllName, EntryPoint = "sp_packet_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern Packet* sp_packet_try_load(byte* data, nuint length);
 
         /// <summary>Deallocates a `Packet`.  Note: do not call this if the instance has been consumed in another way, e.g. by sending it.</summary>
-        [DllImport(__DllName, EntryPoint = "sp2_packet_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
-        public static extern void sp2_packet_dealloc(Packet* @this);
+        [DllImport(__DllName, EntryPoint = "sp_packet_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        public static extern void sp_packet_dealloc(Packet* @this);
 
 
     }
 
+    [StructLayout(LayoutKind.Sequential)]
+    public unsafe partial struct CByteSlice
+    {
+        public byte* start;
+        public nuint length;
+    }
+
     [StructLayout(LayoutKind.Sequential)]
     public unsafe partial struct BitVec
     {
@@ -244,13 +254,6 @@ namespace ServicePoint.BindGen
     {
     }
 
-    [StructLayout(LayoutKind.Sequential)]
-    public unsafe partial struct CByteSlice
-    {
-        public byte* start;
-        public nuint length;
-    }
-
     [StructLayout(LayoutKind.Sequential)]
     public unsafe partial struct Packet
     {
diff --git a/crates/servicepoint_binding_cs/src/BitVec.cs b/crates/servicepoint_binding_cs/ServicePoint/BitVec.cs
similarity index 63%
rename from crates/servicepoint_binding_cs/src/BitVec.cs
rename to crates/servicepoint_binding_cs/ServicePoint/BitVec.cs
index 3d61d92..13b2200 100644
--- a/crates/servicepoint_binding_cs/src/BitVec.cs
+++ b/crates/servicepoint_binding_cs/ServicePoint/BitVec.cs
@@ -8,7 +8,7 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
     {
         unsafe
         {
-            return new BitVec(NativeMethods.sp2_bit_vec_new((nuint)size));
+            return new BitVec(NativeMethods.sp_bit_vec_new((nuint)size));
         }
     }
 
@@ -18,7 +18,7 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
         {
             fixed (byte* bytesPtr = bytes)
             {
-                return new BitVec(NativeMethods.sp2_bit_vec_load(bytesPtr, (nuint)bytes.Length));
+                return new BitVec(NativeMethods.sp_bit_vec_load(bytesPtr, (nuint)bytes.Length));
             }
         }
     }
@@ -27,7 +27,7 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
     {
         unsafe
         {
-            return new BitVec(NativeMethods.sp2_bit_vec_clone(Instance));
+            return new BitVec(NativeMethods.sp_bit_vec_clone(Instance));
         }
     }
 
@@ -37,14 +37,14 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
         {
             unsafe
             {
-                return NativeMethods.sp2_bit_vec_get(Instance, (nuint)index);
+                return NativeMethods.sp_bit_vec_get(Instance, (nuint)index);
             }
         }
         set
         {
             unsafe
             {
-                NativeMethods.sp2_bit_vec_set(Instance, (nuint)index, value);
+                NativeMethods.sp_bit_vec_set(Instance, (nuint)index, value);
             }
         }
     }
@@ -53,7 +53,7 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
     {
         unsafe
         {
-            NativeMethods.sp2_bit_vec_fill(Instance, value);
+            NativeMethods.sp_bit_vec_fill(Instance, value);
         }
     }
 
@@ -63,7 +63,7 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
         {
             unsafe
             {
-                return (int)NativeMethods.sp2_bit_vec_len(Instance);
+                return (int)NativeMethods.sp_bit_vec_len(Instance);
             }
         }
     }
@@ -74,7 +74,7 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
         {
             unsafe
             {
-                var slice = NativeMethods.sp2_bit_vec_unsafe_data_ref(Instance);
+                var slice = NativeMethods.sp_bit_vec_unsafe_data_ref(Instance);
                 return new Span<byte>(slice.start, (int)slice.length);
             }
         }
@@ -86,6 +86,6 @@ public sealed class BitVec : SpNativeInstance<BindGen.BitVec>
 
     private protected override unsafe void Dealloc()
     {
-        NativeMethods.sp2_bit_vec_dealloc(Instance);
+        NativeMethods.sp_bit_vec_dealloc(Instance);
     }
 }
diff --git a/crates/servicepoint_binding_cs/src/ByteGrid.cs b/crates/servicepoint_binding_cs/ServicePoint/ByteGrid.cs
similarity index 72%
rename from crates/servicepoint_binding_cs/src/ByteGrid.cs
rename to crates/servicepoint_binding_cs/ServicePoint/ByteGrid.cs
index 2722a68..e6c4fdc 100644
--- a/crates/servicepoint_binding_cs/src/ByteGrid.cs
+++ b/crates/servicepoint_binding_cs/ServicePoint/ByteGrid.cs
@@ -9,7 +9,7 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
     {
         unsafe
         {
-            return new ByteGrid(NativeMethods.sp2_byte_grid_new((nuint)width, (nuint)height));
+            return new ByteGrid(NativeMethods.sp_byte_grid_new((nuint)width, (nuint)height));
         }
     }
 
@@ -19,7 +19,7 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
         {
             fixed (byte* bytesPtr = bytes)
             {
-                return new ByteGrid(NativeMethods.sp2_byte_grid_load((nuint)width, (nuint)height, bytesPtr,
+                return new ByteGrid(NativeMethods.sp_byte_grid_load((nuint)width, (nuint)height, bytesPtr,
                     (nuint)bytes.Length));
             }
         }
@@ -29,7 +29,7 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
     {
         unsafe
         {
-            return new ByteGrid(NativeMethods.sp2_byte_grid_clone(Instance));
+            return new ByteGrid(NativeMethods.sp_byte_grid_clone(Instance));
         }
     }
 
@@ -39,14 +39,14 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
         {
             unsafe
             {
-                return NativeMethods.sp2_byte_grid_get(Instance, (nuint)x, (nuint)y);
+                return NativeMethods.sp_byte_grid_get(Instance, (nuint)x, (nuint)y);
             }
         }
         set
         {
             unsafe
             {
-                NativeMethods.sp2_byte_grid_set(Instance, (nuint)x, (nuint)y, value);
+                NativeMethods.sp_byte_grid_set(Instance, (nuint)x, (nuint)y, value);
             }
         }
     }
@@ -85,7 +85,7 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
     {
         unsafe
         {
-            NativeMethods.sp2_byte_grid_fill(Instance, value);
+            NativeMethods.sp_byte_grid_fill(Instance, value);
         }
     }
 
@@ -95,7 +95,7 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
         {
             unsafe
             {
-                return (int)NativeMethods.sp2_byte_grid_width(Instance);
+                return (int)NativeMethods.sp_byte_grid_width(Instance);
             }
         }
     }
@@ -106,7 +106,7 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
         {
             unsafe
             {
-                return (int)NativeMethods.sp2_byte_grid_height(Instance);
+                return (int)NativeMethods.sp_byte_grid_height(Instance);
             }
         }
     }
@@ -117,7 +117,7 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
         {
             unsafe
             {
-                var slice = NativeMethods.sp2_byte_grid_unsafe_data_ref(Instance);
+                var slice = NativeMethods.sp_byte_grid_unsafe_data_ref(Instance);
                 return new Span<byte>(slice.start, (int)slice.length);
             }
         }
@@ -129,6 +129,6 @@ public sealed class ByteGrid : SpNativeInstance<BindGen.ByteGrid>
 
     private protected override unsafe void Dealloc()
     {
-        NativeMethods.sp2_byte_grid_dealloc(Instance);
+        NativeMethods.sp_byte_grid_dealloc(Instance);
     }
 }
diff --git a/crates/servicepoint_binding_cs/src/Command.cs b/crates/servicepoint_binding_cs/ServicePoint/Command.cs
similarity index 64%
rename from crates/servicepoint_binding_cs/src/Command.cs
rename to crates/servicepoint_binding_cs/ServicePoint/Command.cs
index b25b564..b9d0d3c 100644
--- a/crates/servicepoint_binding_cs/src/Command.cs
+++ b/crates/servicepoint_binding_cs/ServicePoint/Command.cs
@@ -9,7 +9,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
     {
         unsafe
         {
-            var result = NativeMethods.sp2_command_try_from_packet(packet.Into());
+            var result = NativeMethods.sp_command_try_from_packet(packet.Into());
             if (result == null)
             {
                 command = null;
@@ -25,7 +25,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
     {
         unsafe
         {
-            return new Command(NativeMethods.sp2_command_clone(Instance));
+            return new Command(NativeMethods.sp_command_clone(Instance));
         }
     }
 
@@ -33,7 +33,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
     {
         unsafe
         {
-            return new Command(NativeMethods.sp2_command_clear());
+            return new Command(NativeMethods.sp_command_clear());
         }
     }
 
@@ -41,7 +41,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
     {
         unsafe
         {
-            return new Command(NativeMethods.sp2_command_hard_reset());
+            return new Command(NativeMethods.sp_command_hard_reset());
         }
     }
 
@@ -49,7 +49,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
     {
         unsafe
         {
-            return new Command(NativeMethods.sp2_command_fade_out());
+            return new Command(NativeMethods.sp_command_fade_out());
         }
     }
 
@@ -57,7 +57,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
     {
         unsafe
         {
-            return new Command(NativeMethods.sp2_command_brightness(brightness));
+            return new Command(NativeMethods.sp_command_brightness(brightness));
         }
     }
 
@@ -65,7 +65,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
     {
         unsafe
         {
-            return new Command(NativeMethods.sp2_command_char_brightness((ushort)x, (ushort)y, grid.Into()));
+            return new Command(NativeMethods.sp_command_char_brightness((ushort)x, (ushort)y, grid.Into()));
         }
     }
 
@@ -74,7 +74,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
         unsafe
         {
             return new Command(
-                NativeMethods.sp2_command_bitmap_linear((ushort)offset, bitVec.Into(), compressionCode));
+                NativeMethods.sp_command_bitmap_linear((ushort)offset, bitVec.Into(), compressionCode));
         }
     }
 
@@ -83,7 +83,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
         unsafe
         {
             return new Command(
-                NativeMethods.sp2_command_bitmap_linear_and((ushort)offset, bitVec.Into(), compressionCode));
+                NativeMethods.sp_command_bitmap_linear_and((ushort)offset, bitVec.Into(), compressionCode));
         }
     }
 
@@ -92,7 +92,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
         unsafe
         {
             return new Command(
-                NativeMethods.sp2_command_bitmap_linear_or((ushort)offset, bitVec.Into(), compressionCode));
+                NativeMethods.sp_command_bitmap_linear_or((ushort)offset, bitVec.Into(), compressionCode));
         }
     }
 
@@ -101,7 +101,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
         unsafe
         {
             return new Command(
-                NativeMethods.sp2_command_bitmap_linear_xor((ushort)offset, bitVec.Into(), compressionCode));
+                NativeMethods.sp_command_bitmap_linear_xor((ushort)offset, bitVec.Into(), compressionCode));
         }
     }
 
@@ -109,7 +109,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
     {
         unsafe
         {
-            return new Command(NativeMethods.sp2_command_bitmap_linear_win((ushort)x, (ushort)y, pixelGrid.Into(), compression));
+            return new Command(NativeMethods.sp_command_bitmap_linear_win((ushort)x, (ushort)y, pixelGrid.Into(), compression));
         }
     }
 
@@ -117,7 +117,7 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
     {
         unsafe
         {
-            return new Command(NativeMethods.sp2_command_cp437_data((ushort)x, (ushort)y, byteGrid.Into()));
+            return new Command(NativeMethods.sp_command_cp437_data((ushort)x, (ushort)y, byteGrid.Into()));
         }
     }
 
@@ -127,6 +127,6 @@ public sealed class Command : SpNativeInstance<BindGen.Command>
 
     private protected override unsafe void Dealloc()
     {
-        NativeMethods.sp2_command_dealloc(Instance);
+        NativeMethods.sp_command_dealloc(Instance);
     }
 }
diff --git a/crates/servicepoint_binding_cs/src/Connection.cs b/crates/servicepoint_binding_cs/ServicePoint/Connection.cs
similarity index 72%
rename from crates/servicepoint_binding_cs/src/Connection.cs
rename to crates/servicepoint_binding_cs/ServicePoint/Connection.cs
index 0f95709..3d1a480 100644
--- a/crates/servicepoint_binding_cs/src/Connection.cs
+++ b/crates/servicepoint_binding_cs/ServicePoint/Connection.cs
@@ -11,7 +11,7 @@ public sealed class Connection : SpNativeInstance<BindGen.Connection>
         {
             fixed (byte* bytePtr = Encoding.UTF8.GetBytes(host))
             {
-                return new Connection(NativeMethods.sp2_connection_open(bytePtr));
+                return new Connection(NativeMethods.sp_connection_open(bytePtr));
             }
         }
     }
@@ -20,13 +20,13 @@ public sealed class Connection : SpNativeInstance<BindGen.Connection>
     {
         unsafe
         {
-            return NativeMethods.sp2_connection_send(Instance, packet.Into());
+            return NativeMethods.sp_connection_send(Instance, packet.Into());
         }
     }
 
     private protected override unsafe void Dealloc()
     {
-        NativeMethods.sp2_connection_dealloc(Instance);
+        NativeMethods.sp_connection_dealloc(Instance);
     }
 
     private unsafe Connection(BindGen.Connection* instance) : base(instance)
diff --git a/crates/servicepoint_binding_cs/src/Constants.cs b/crates/servicepoint_binding_cs/ServicePoint/Constants.cs
similarity index 100%
rename from crates/servicepoint_binding_cs/src/Constants.cs
rename to crates/servicepoint_binding_cs/ServicePoint/Constants.cs
diff --git a/crates/servicepoint_binding_cs/src/GlobalUsings.cs b/crates/servicepoint_binding_cs/ServicePoint/GlobalUsings.cs
similarity index 100%
rename from crates/servicepoint_binding_cs/src/GlobalUsings.cs
rename to crates/servicepoint_binding_cs/ServicePoint/GlobalUsings.cs
diff --git a/crates/servicepoint_binding_cs/src/Packet.cs b/crates/servicepoint_binding_cs/ServicePoint/Packet.cs
similarity index 76%
rename from crates/servicepoint_binding_cs/src/Packet.cs
rename to crates/servicepoint_binding_cs/ServicePoint/Packet.cs
index 822e601..ab4b08a 100644
--- a/crates/servicepoint_binding_cs/src/Packet.cs
+++ b/crates/servicepoint_binding_cs/ServicePoint/Packet.cs
@@ -9,7 +9,7 @@ public sealed class Packet : SpNativeInstance<BindGen.Packet>
     {
         unsafe
         {
-            return new Packet(NativeMethods.sp2_packet_from_command(command.Into()));
+            return new Packet(NativeMethods.sp_packet_from_command(command.Into()));
         }
     }
 
@@ -19,7 +19,7 @@ public sealed class Packet : SpNativeInstance<BindGen.Packet>
         {
             fixed (byte* bytesPtr = bytes)
             {
-                var instance = NativeMethods.sp2_packet_try_load(bytesPtr, (nuint)bytes.Length);
+                var instance = NativeMethods.sp_packet_try_load(bytesPtr, (nuint)bytes.Length);
                 packet = instance == null
                     ? null
                     : new Packet(instance);
@@ -34,6 +34,6 @@ public sealed class Packet : SpNativeInstance<BindGen.Packet>
 
     private protected override unsafe void Dealloc()
     {
-        NativeMethods.sp2_packet_dealloc(Instance);
+        NativeMethods.sp_packet_dealloc(Instance);
     }
 }
diff --git a/crates/servicepoint_binding_cs/src/PixelGrid.cs b/crates/servicepoint_binding_cs/ServicePoint/PixelGrid.cs
similarity index 63%
rename from crates/servicepoint_binding_cs/src/PixelGrid.cs
rename to crates/servicepoint_binding_cs/ServicePoint/PixelGrid.cs
index 2d12f93..1e6fb11 100644
--- a/crates/servicepoint_binding_cs/src/PixelGrid.cs
+++ b/crates/servicepoint_binding_cs/ServicePoint/PixelGrid.cs
@@ -8,7 +8,7 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
     {
         unsafe
         {
-            return new PixelGrid(NativeMethods.sp2_pixel_grid_new((nuint)width, (nuint)height));
+            return new PixelGrid(NativeMethods.sp_pixel_grid_new((nuint)width, (nuint)height));
         }
     }
 
@@ -18,7 +18,7 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
         {
             fixed (byte* bytesPtr = bytes)
             {
-                return new PixelGrid(NativeMethods.sp2_pixel_grid_load((nuint)width, (nuint)height, bytesPtr,
+                return new PixelGrid(NativeMethods.sp_pixel_grid_load((nuint)width, (nuint)height, bytesPtr,
                     (nuint)bytes.Length));
             }
         }
@@ -28,7 +28,7 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
     {
         unsafe
         {
-            return new PixelGrid(NativeMethods.sp2_pixel_grid_clone(Instance));
+            return new PixelGrid(NativeMethods.sp_pixel_grid_clone(Instance));
         }
     }
 
@@ -38,14 +38,14 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
         {
             unsafe
             {
-                return NativeMethods.sp2_pixel_grid_get(Instance, (nuint)x, (nuint)y);
+                return NativeMethods.sp_pixel_grid_get(Instance, (nuint)x, (nuint)y);
             }
         }
         set
         {
             unsafe
             {
-                NativeMethods.sp2_pixel_grid_set(Instance, (nuint)x, (nuint)y, value);
+                NativeMethods.sp_pixel_grid_set(Instance, (nuint)x, (nuint)y, value);
             }
         }
     }
@@ -54,7 +54,7 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
     {
         unsafe
         {
-            NativeMethods.sp2_pixel_grid_fill(Instance, value);
+            NativeMethods.sp_pixel_grid_fill(Instance, value);
         }
     }
 
@@ -64,7 +64,7 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
         {
             unsafe
             {
-                return (int)NativeMethods.sp2_pixel_grid_width(Instance);
+                return (int)NativeMethods.sp_pixel_grid_width(Instance);
             }
         }
     }
@@ -75,7 +75,7 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
         {
             unsafe
             {
-                return (int)NativeMethods.sp2_pixel_grid_height(Instance);
+                return (int)NativeMethods.sp_pixel_grid_height(Instance);
             }
         }
     }
@@ -86,7 +86,7 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
         {
             unsafe
             {
-                var slice = NativeMethods.sp2_pixel_grid_unsafe_data_ref(Instance);
+                var slice = NativeMethods.sp_pixel_grid_unsafe_data_ref(Instance);
                 return new Span<byte>(slice.start, (int)slice.length);
             }
         }
@@ -98,6 +98,6 @@ public sealed class PixelGrid : SpNativeInstance<BindGen.PixelGrid>
 
     private protected override unsafe void Dealloc()
     {
-        NativeMethods.sp2_pixel_grid_dealloc(Instance);
+        NativeMethods.sp_pixel_grid_dealloc(Instance);
     }
 }
diff --git a/crates/servicepoint_binding_cs/src/ServicePoint.csproj b/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj
similarity index 74%
rename from crates/servicepoint_binding_cs/src/ServicePoint.csproj
rename to crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj
index f090283..e82c589 100644
--- a/crates/servicepoint_binding_cs/src/ServicePoint.csproj
+++ b/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj
@@ -26,45 +26,39 @@
         <PublishRepositoryUrl>true</PublishRepositoryUrl>
     </PropertyGroup>
 
-    <Target Name="BuildLibrary" Condition="'$(Configuration)'=='Release'" BeforeTargets="Build">
-        <Exec Command="cargo build --manifest-path ../../servicepoint/Cargo.toml --all-features --release"/>
-    </Target>
-
-    <Target Name="BuildLibrary" Condition="'$(Configuration)'=='Debug'" BeforeTargets="Build">
-        <Exec Command="cargo build --manifest-path ../../servicepoint/Cargo.toml --all-features"/>
-    </Target>
-
+    <!-- generate C# bindings -->
     <Target Name="BuildBindings" Condition="'$(Configuration)'=='Release'" BeforeTargets="Build">
         <Exec Command="cargo build --release"/>
     </Target>
-
     <Target Name="BuildBindings" Condition="'$(Configuration)'=='Debug'" BeforeTargets="Build">
         <Exec Command="cargo build"/>
     </Target>
 
+    <!-- build native library to include in output -->
+    <Target Name="BuildLibrary" Condition="'$(Configuration)'=='Release'" BeforeTargets="Build">
+        <Exec Command="cargo build --manifest-path ../../../crates/servicepoint/Cargo.toml --release"/>
+    </Target>
+    <Target Name="BuildLibrary" Condition="'$(Configuration)'=='Debug'" BeforeTargets="Build">
+        <Exec Command="cargo build --manifest-path ../../../crates/servicepoint/Cargo.toml"/>
+    </Target>
+
+    <!-- include native binary in output -->
     <ItemGroup Condition="'$(Configuration)'=='Debug'">
-        <Content Include="../../target/debug/libservicepoint.so" CopyToOutputDirectory="Always">
-            <Link>libservicepoint.so</Link>
+        <Content Include="../../../target/debug/libservicepoint_binding_c.so" CopyToOutputDirectory="Always">
+            <Link>libservicepoint_binding_c.so</Link>
         </Content>
     </ItemGroup>
-
     <ItemGroup Condition="'$(Configuration)'=='Release'">
-        <Content Include="../../target/release/libservicepoint.so" CopyToOutputDirectory="Always">
-            <Link>libservicepoint.so</Link>
+        <Content Include="../../../target/release/libservicepoint_binding_c.so" CopyToOutputDirectory="Always">
+            <Link>libservicepoint_binding_c.so</Link>
         </Content>
     </ItemGroup>
 
     <ItemGroup>
         <!-- include link to source code at revision -->
-        <None Include="../../README.md" Pack="true" PackagePath="\"/>
+        <None Include="../../../README.md" Pack="true" PackagePath="\"/>
         <!-- add README.md to package -->
         <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
     </ItemGroup>
 
-    <ItemGroup>
-      <Content Include="..\build.rs">
-        <Link>build.rs</Link>
-      </Content>
-    </ItemGroup>
-
 </Project>
diff --git a/crates/servicepoint_binding_cs/src/ServicePointExtensions.cs b/crates/servicepoint_binding_cs/ServicePoint/ServicePointExtensions.cs
similarity index 100%
rename from crates/servicepoint_binding_cs/src/ServicePointExtensions.cs
rename to crates/servicepoint_binding_cs/ServicePoint/ServicePointExtensions.cs
diff --git a/crates/servicepoint_binding_cs/src/SpNativeInstance.cs b/crates/servicepoint_binding_cs/ServicePoint/SpNativeInstance.cs
similarity index 100%
rename from crates/servicepoint_binding_cs/src/SpNativeInstance.cs
rename to crates/servicepoint_binding_cs/ServicePoint/SpNativeInstance.cs
diff --git a/crates/servicepoint_binding_cs/build.rs b/crates/servicepoint_binding_cs/build.rs
index 23a0377..ec5aa81 100644
--- a/crates/servicepoint_binding_cs/build.rs
+++ b/crates/servicepoint_binding_cs/build.rs
@@ -1,19 +1,28 @@
 fn main() {
-    println!("cargo:rerun-if-changed=DOESNOTEXIST"); // rebuild every time
+    println!("cargo:rerun-if-changed=../servicepoint_binding_c/src");
+    println!("cargo:rerun-if-changed=build.rs");
     csbindgen::Builder::default()
+        .input_extern_file("../servicepoint_binding_c/src/bit_vec.rs")
+        .input_extern_file("../servicepoint_binding_c/src/byte_grid.rs")
+        .input_extern_file("../servicepoint_binding_c/src/command.rs")
+        .input_extern_file("../servicepoint_binding_c/src/connection.rs")
+        .input_extern_file("../servicepoint_binding_c/src/pixel_grid.rs")
+        .input_extern_file("../servicepoint_binding_c/src/lib.rs")
+        .input_extern_file("../servicepoint_binding_c/src/c_slice.rs")
+        .input_extern_file("../servicepoint_binding_c/src/packet.rs")
         .input_extern_file("../servicepoint/src/bit_vec.rs")
         .input_extern_file("../servicepoint/src/byte_grid.rs")
         .input_extern_file("../servicepoint/src/command.rs")
-        .input_extern_file("../servicepoint/src/compression_code.rs")
         .input_extern_file("../servicepoint/src/connection.rs")
         .input_extern_file("../servicepoint/src/pixel_grid.rs")
         .input_extern_file("../servicepoint/src/lib.rs")
-        .input_extern_file("../servicepoint/src/c_slice.rs")
         .input_extern_file("../servicepoint/src/packet.rs")
-        .csharp_dll_name("servicepoint")
+        .input_extern_file("../servicepoint/src/compression_code.rs")
+        .csharp_dll_name("servicepoint_binding_c")
         .csharp_namespace("ServicePoint.BindGen")
         .csharp_use_nint_types(true)
         .csharp_class_accessibility("public")
-        .generate_csharp_file("src/BindGen/ServicePoint.g.cs")
+        .csharp_generate_const_filter(|_| true)
+        .generate_csharp_file("ServicePoint/BindGen/ServicePoint.g.cs")
         .unwrap();
 }
diff --git a/examples/lang_c/Makefile b/examples/lang_c/Makefile
index 825510a..787d38e 100644
--- a/examples/lang_c/Makefile
+++ b/examples/lang_c/Makefile
@@ -15,22 +15,19 @@ run: out/lang_c
 PHONY: build clean dependencies run
 
 out/lang_c: dependencies src/main.c
-	mkdir out || true
+	mkdir -p out || true
 	${CC} src/main.c \
 		-I include \
 		-L $(REPO_ROOT)/target/release \
-		-Wl,-Bstatic -lservicepoint \
+		-Wl,-Bstatic -lservicepoint_binding_c \
 		-Wl,-Bdynamic -llzma \
-		-o out/lang_c \
+		-o out/lang_c
 
 dependencies: FORCE
-	mkdir include || true
-	# generate servicepoint header
+	mkdir -p include || true
+	# generate servicepoint header and binary to link against
 	SERVICEPOINT_HEADER_OUT=$(THIS_DIR)/include cargo build \
-		--manifest-path=$(REPO_ROOT)/crates/servicepoint_binding_c/Cargo.toml
-
-	# build release binary to link against
-	cargo build --manifest-path=$(REPO_ROOT)/crates/servicepoint/Cargo.toml --release \
-		--features c_api,all_compressions
+		--manifest-path=$(REPO_ROOT)/crates/servicepoint_binding_c/Cargo.toml \
+		--release
 
 FORCE: ;
diff --git a/examples/lang_c/build.rs b/examples/lang_c/build.rs
index 56b5b89..279439f 100644
--- a/examples/lang_c/build.rs
+++ b/examples/lang_c/build.rs
@@ -1,11 +1,12 @@
-fn main() {
-    println!("cargo::rerun-if-changed=src/main.c");
-    println!("cargo::rerun-if-changed=build.rs");
+const SP_INCLUDE: &str = "DEP_SERVICEPOINT_INCLUDE";
 
-    let sp_include = std::env::var_os("DEP_SERVICEPOINT_INCLUDE")
-        .unwrap()
-        .into_string()
-        .unwrap();
+fn main() {
+    println!("cargo:rerun-if-changed=src/main.c");
+    println!("cargo:rerun-if-changed=build.rs");
+    println!("cargo:rerun-if-env-changed={SP_INCLUDE}");
+
+    let sp_include =
+        std::env::var_os(SP_INCLUDE).unwrap().into_string().unwrap();
 
     // this builds a lib, this is only to check that the example compiles
     let mut cc = cc::Build::new();
diff --git a/examples/lang_c/include/servicepoint.h b/examples/lang_c/include/servicepoint.h
index 694409d..cc1e903 100644
--- a/examples/lang_c/include/servicepoint.h
+++ b/examples/lang_c/include/servicepoint.h
@@ -9,95 +9,87 @@
 /**
  * pixel count on whole screen
  */
-#define sp2_PIXEL_COUNT (sp2_PIXEL_WIDTH * sp2_PIXEL_HEIGHT)
+#define sp_PIXEL_COUNT (sp_PIXEL_WIDTH * sp_PIXEL_HEIGHT)
 
 /**
  * screen height in pixels
  */
-#define sp2_PIXEL_HEIGHT (sp2_TILE_HEIGHT * sp2_TILE_SIZE)
+#define sp_PIXEL_HEIGHT (sp_TILE_HEIGHT * sp_TILE_SIZE)
 
 /**
  * screen width in pixels
  */
-#define sp2_PIXEL_WIDTH (sp2_TILE_WIDTH * sp2_TILE_SIZE)
+#define sp_PIXEL_WIDTH (sp_TILE_WIDTH * sp_TILE_SIZE)
 
 /**
  * tile count in the y-direction
  */
-#define sp2_TILE_HEIGHT 20
+#define sp_TILE_HEIGHT 20
 
 /**
  * size of a single tile in one dimension
  */
-#define sp2_TILE_SIZE 8
+#define sp_TILE_SIZE 8
 
 /**
  * tile count in the x-direction
  */
-#define sp2_TILE_WIDTH 56
+#define sp_TILE_WIDTH 56
 
 /**
  * Specifies the kind of compression to use. Availability depends on features.
  */
-enum sp2_CompressionCode
+enum sp_CompressionCode
 #ifdef __cplusplus
   : uint16_t
 #endif // __cplusplus
  {
     Uncompressed = 0,
-#if defined(SP2_FEATURE_compression_zlib)
     Zlib = 26490,
-#endif
-#if defined(SP2_FEATURE_compression_bzip2)
     Bzip2 = 25210,
-#endif
-#if defined(SP2_FEATURE_compression_lzma)
     Lzma = 27770,
-#endif
-#if defined(SP2_FEATURE_compression_zstd)
     Zstd = 31347,
-#endif
 };
 #ifndef __cplusplus
-typedef uint16_t sp2_CompressionCode;
+typedef uint16_t sp_CompressionCode;
 #endif // __cplusplus
 
 /**
  * A vector of bits
  */
-typedef struct sp2_BitVec sp2_BitVec;
+typedef struct sp_BitVec sp_BitVec;
 
 /**
  * A 2D grid of bytes
  */
-typedef struct sp2_ByteGrid sp2_ByteGrid;
+typedef struct sp_ByteGrid sp_ByteGrid;
 
 /**
  * A command to send to the display.
  */
-typedef struct sp2_Command sp2_Command;
+typedef struct sp_Command sp_Command;
 
 /**
  * A connection to the display.
  */
-typedef struct sp2_Connection sp2_Connection;
+typedef struct sp_Connection sp_Connection;
 
 /**
  * The raw packet. Should probably not be used directly.
  */
-typedef struct sp2_Packet sp2_Packet;
+typedef struct sp_Packet sp_Packet;
 
 /**
  * A grid of pixels stored in packed bytes.
  */
-typedef struct sp2_PixelGrid sp2_PixelGrid;
+typedef struct sp_PixelGrid sp_PixelGrid;
 
 /**
  * Represents a span of memory (`&mut [u8]` ) as a struct usable by C code.
  *
  * Usage of this type is inherently unsafe.
  */
-typedef struct sp2_CByteSlice {
+typedef struct sp_CByteSlice {
     /**
      * The start address of the memory
      */
@@ -106,17 +98,17 @@ typedef struct sp2_CByteSlice {
      * The amount of memory in bytes
      */
     size_t length;
-} sp2_CByteSlice;
+} sp_CByteSlice;
 
 /**
  * Type alias for documenting the meaning of the u16 in enum values
  */
-typedef size_t sp2_Offset;
+typedef size_t sp_Offset;
 
 /**
  * Type alias for documenting the meaning of the u16 in enum values
  */
-typedef uint8_t sp2_Brightness;
+typedef uint8_t sp_Brightness;
 
 #ifdef __cplusplus
 extern "C" {
@@ -126,51 +118,51 @@ extern "C" {
  * Clones a `BitVec`.
  * The returned instance has to be freed with `bit_vec_dealloc`.
  */
-struct sp2_BitVec *sp2_bit_vec_clone(const struct sp2_BitVec *this_);
+struct sp_BitVec *sp_bit_vec_clone(const struct sp_BitVec *this_);
 
 /**
  * Deallocates a `BitVec`.
  *
  * Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
  */
-void sp2_bit_vec_dealloc(struct sp2_BitVec *this_);
+void sp_bit_vec_dealloc(struct sp_BitVec *this_);
 
 /**
  * Sets the value of all bits in the `BitVec`.
  */
-void sp2_bit_vec_fill(struct sp2_BitVec *this_, bool value);
+void sp_bit_vec_fill(struct sp_BitVec *this_, bool value);
 
 /**
  * Gets the value of a bit from the `BitVec`.
  */
-bool sp2_bit_vec_get(const struct sp2_BitVec *this_, size_t index);
+bool sp_bit_vec_get(const struct sp_BitVec *this_, size_t index);
 
 /**
  * Returns true if length is 0.
  */
-bool sp2_bit_vec_is_empty(const struct sp2_BitVec *this_);
+bool sp_bit_vec_is_empty(const struct sp_BitVec *this_);
 
 /**
  * Gets the length of the `BitVec` in bits.
  */
-size_t sp2_bit_vec_len(const struct sp2_BitVec *this_);
+size_t sp_bit_vec_len(const struct sp_BitVec *this_);
 
 /**
  * Loads a `BitVec` from the provided data.
  * The returned instance has to be freed with `bit_vec_dealloc`.
  */
-struct sp2_BitVec *sp2_bit_vec_load(const uint8_t *data, size_t data_length);
+struct sp_BitVec *sp_bit_vec_load(const uint8_t *data, size_t data_length);
 
 /**
  * Creates a new `BitVec` instance.
  * The returned instance has to be freed with `bit_vec_dealloc`.
  */
-struct sp2_BitVec *sp2_bit_vec_new(size_t size);
+struct sp_BitVec *sp_bit_vec_new(size_t size);
 
 /**
  * Sets the value of a bit in the `BitVec`.
  */
-bool sp2_bit_vec_set(struct sp2_BitVec *this_, size_t index, bool value);
+bool sp_bit_vec_set(struct sp_BitVec *this_, size_t index, bool value);
 
 /**
  * Gets an unsafe reference to the data of the `BitVec` instance.
@@ -183,58 +175,58 @@ bool sp2_bit_vec_set(struct sp2_BitVec *this_, size_t index, bool value);
  * Reading and writing concurrently to either the original instance or the returned data will
  * result in undefined behavior.
  */
-struct sp2_CByteSlice sp2_bit_vec_unsafe_data_ref(struct sp2_BitVec *this_);
+struct sp_CByteSlice sp_bit_vec_unsafe_data_ref(struct sp_BitVec *this_);
 
 /**
  * Clones a `ByteGrid`.
  * The returned instance has to be freed with `byte_grid_dealloc`.
  */
-struct sp2_ByteGrid *sp2_byte_grid_clone(const struct sp2_ByteGrid *this_);
+struct sp_ByteGrid *sp_byte_grid_clone(const struct sp_ByteGrid *this_);
 
 /**
  * Deallocates a `ByteGrid`.
  *
  * Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
  */
-void sp2_byte_grid_dealloc(struct sp2_ByteGrid *this_);
+void sp_byte_grid_dealloc(struct sp_ByteGrid *this_);
 
 /**
  * Fills the whole `ByteGrid` with the specified value
  */
-void sp2_byte_grid_fill(struct sp2_ByteGrid *this_, uint8_t value);
+void sp_byte_grid_fill(struct sp_ByteGrid *this_, uint8_t value);
 
 /**
  * Get the current value at the specified position
  */
-uint8_t sp2_byte_grid_get(const struct sp2_ByteGrid *this_, size_t x, size_t y);
+uint8_t sp_byte_grid_get(const struct sp_ByteGrid *this_, size_t x, size_t y);
 
 /**
  * Gets the height in pixels of the `ByteGrid` instance.
  */
-size_t sp2_byte_grid_height(const struct sp2_ByteGrid *this_);
+size_t sp_byte_grid_height(const struct sp_ByteGrid *this_);
 
 /**
  * Loads a `ByteGrid` with the specified dimensions from the provided data.
  * The returned instance has to be freed with `byte_grid_dealloc`.
  */
-struct sp2_ByteGrid *sp2_byte_grid_load(size_t width,
-                                        size_t height,
-                                        const uint8_t *data,
-                                        size_t data_length);
+struct sp_ByteGrid *sp_byte_grid_load(size_t width,
+                                      size_t height,
+                                      const uint8_t *data,
+                                      size_t data_length);
 
 /**
  * Creates a new `ByteGrid` instance.
  * The returned instance has to be freed with `byte_grid_dealloc`.
  */
-struct sp2_ByteGrid *sp2_byte_grid_new(size_t width, size_t height);
+struct sp_ByteGrid *sp_byte_grid_new(size_t width, size_t height);
 
 /**
  * Sets the current value at the specified position
  */
-void sp2_byte_grid_set(struct sp2_ByteGrid *this_,
-                       size_t x,
-                       size_t y,
-                       uint8_t value);
+void sp_byte_grid_set(struct sp_ByteGrid *this_,
+                      size_t x,
+                      size_t y,
+                      uint8_t value);
 
 /**
  * Gets an unsafe reference to the data of the `ByteGrid` instance.
@@ -247,112 +239,112 @@ void sp2_byte_grid_set(struct sp2_ByteGrid *this_,
  * Reading and writing concurrently to either the original instance or the returned data will
  * result in undefined behavior.
  */
-struct sp2_CByteSlice sp2_byte_grid_unsafe_data_ref(struct sp2_ByteGrid *this_);
+struct sp_CByteSlice sp_byte_grid_unsafe_data_ref(struct sp_ByteGrid *this_);
 
 /**
  * Gets the width in pixels of the `ByteGrid` instance.
  */
-size_t sp2_byte_grid_width(const struct sp2_ByteGrid *this_);
+size_t sp_byte_grid_width(const struct sp_ByteGrid *this_);
 
 /**
  * Allocates a new `Command::BitmapLinear` instance.
  * The passed `BitVec` gets deallocated in the process.
  */
-struct sp2_Command *sp2_command_bitmap_linear(sp2_Offset offset,
-                                              struct sp2_BitVec *bit_vec,
-                                              sp2_CompressionCode compression);
+struct sp_Command *sp_command_bitmap_linear(sp_Offset offset,
+                                            struct sp_BitVec *bit_vec,
+                                            sp_CompressionCode compression);
 
 /**
  * Allocates a new `Command::BitmapLinearAnd` instance.
  * The passed `BitVec` gets deallocated in the process.
  */
-struct sp2_Command *sp2_command_bitmap_linear_and(sp2_Offset offset,
-                                                  struct sp2_BitVec *bit_vec,
-                                                  sp2_CompressionCode compression);
+struct sp_Command *sp_command_bitmap_linear_and(sp_Offset offset,
+                                                struct sp_BitVec *bit_vec,
+                                                sp_CompressionCode compression);
 
 /**
  * Allocates a new `Command::BitmapLinearOr` instance.
  * The passed `BitVec` gets deallocated in the process.
  */
-struct sp2_Command *sp2_command_bitmap_linear_or(sp2_Offset offset,
-                                                 struct sp2_BitVec *bit_vec,
-                                                 sp2_CompressionCode compression);
+struct sp_Command *sp_command_bitmap_linear_or(sp_Offset offset,
+                                               struct sp_BitVec *bit_vec,
+                                               sp_CompressionCode compression);
 
 /**
  * Allocates a new `Command::BitmapLinearWin` instance.
  * The passed `PixelGrid` gets deallocated in the process.
  */
-struct sp2_Command *sp2_command_bitmap_linear_win(size_t x,
-                                                  size_t y,
-                                                  struct sp2_PixelGrid *byte_grid,
-                                                  sp2_CompressionCode compression_code);
+struct sp_Command *sp_command_bitmap_linear_win(size_t x,
+                                                size_t y,
+                                                struct sp_PixelGrid *byte_grid,
+                                                sp_CompressionCode compression_code);
 
 /**
  * Allocates a new `Command::BitmapLinearXor` instance.
  * The passed `BitVec` gets deallocated in the process.
  */
-struct sp2_Command *sp2_command_bitmap_linear_xor(sp2_Offset offset,
-                                                  struct sp2_BitVec *bit_vec,
-                                                  sp2_CompressionCode compression);
+struct sp_Command *sp_command_bitmap_linear_xor(sp_Offset offset,
+                                                struct sp_BitVec *bit_vec,
+                                                sp_CompressionCode compression);
 
 /**
  * Allocates a new `Command::Brightness` instance
  */
-struct sp2_Command *sp2_command_brightness(sp2_Brightness brightness);
+struct sp_Command *sp_command_brightness(sp_Brightness brightness);
 
 /**
  * Allocates a new `Command::CharBrightness` instance.
  * The passed `ByteGrid` gets deallocated in the process.
  */
-struct sp2_Command *sp2_command_char_brightness(size_t x,
-                                                size_t y,
-                                                struct sp2_ByteGrid *byte_grid);
+struct sp_Command *sp_command_char_brightness(size_t x,
+                                              size_t y,
+                                              struct sp_ByteGrid *byte_grid);
 
 /**
  * Allocates a new `Command::Clear` instance
  */
-struct sp2_Command *sp2_command_clear(void);
+struct sp_Command *sp_command_clear(void);
 
 /**
  * Clones a `Command` instance
  */
-struct sp2_Command *sp2_command_clone(const struct sp2_Command *original);
+struct sp_Command *sp_command_clone(const struct sp_Command *original);
 
 /**
  * Allocates a new `Command::Cp437Data` instance.
  * The passed `ByteGrid` gets deallocated in the process.
  */
-struct sp2_Command *sp2_command_cp437_data(size_t x,
-                                           size_t y,
-                                           struct sp2_ByteGrid *byte_grid);
+struct sp_Command *sp_command_cp437_data(size_t x,
+                                         size_t y,
+                                         struct sp_ByteGrid *byte_grid);
 
 /**
  * Deallocates a `Command`. Note that connection_send does this implicitly, so you only need
  * to do this if you use the library for parsing commands.
  */
-void sp2_command_dealloc(struct sp2_Command *ptr);
+void sp_command_dealloc(struct sp_Command *ptr);
 
 /**
  * Allocates a new `Command::FadeOut` instance
  */
-struct sp2_Command *sp2_command_fade_out(void);
+struct sp_Command *sp_command_fade_out(void);
 
 /**
  * Allocates a new `Command::HardReset` instance
  */
-struct sp2_Command *sp2_command_hard_reset(void);
+struct sp_Command *sp_command_hard_reset(void);
 
 /**
  * Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process.
  *
  * Returns: pointer to command or NULL
  */
-struct sp2_Command *sp2_command_try_from_packet(struct sp2_Packet *packet);
+struct sp_Command *sp_command_try_from_packet(struct sp_Packet *packet);
 
 /**
  * Closes and deallocates a connection instance
  */
-void sp2_connection_dealloc(struct sp2_Connection *ptr);
+void sp_connection_dealloc(struct sp_Connection *ptr);
 
 /**
  * Creates a new instance of Connection.
@@ -362,83 +354,83 @@ void sp2_connection_dealloc(struct sp2_Connection *ptr);
  *
  * Panics: bad string encoding
  */
-struct sp2_Connection *sp2_connection_open(const char *host);
+struct sp_Connection *sp_connection_open(const char *host);
 
 /**
  * Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.
  */
-bool sp2_connection_send(const struct sp2_Connection *connection,
-                         struct sp2_Packet *command_ptr);
+bool sp_connection_send(const struct sp_Connection *connection,
+                        struct sp_Packet *command_ptr);
 
 /**
  * Deallocates a `Packet`.
  *
  * Note: do not call this if the instance has been consumed in another way, e.g. by sending it.
  */
-void sp2_packet_dealloc(struct sp2_Packet *this_);
+void sp_packet_dealloc(struct sp_Packet *this_);
 
 /**
  * Turns a `Command` into a `Packet`. The command gets deallocated in the process.
  */
-struct sp2_Packet *sp2_packet_from_command(struct sp2_Command *command);
+struct sp_Packet *sp_packet_from_command(struct sp_Command *command);
 
 /**
  * Tries to load a `Packet` from the passed array with the specified length.
  *
  * returns: NULL in case of an error, pointer to the allocated packet otherwise
  */
-struct sp2_Packet *sp2_packet_try_load(const uint8_t *data, size_t length);
+struct sp_Packet *sp_packet_try_load(const uint8_t *data, size_t length);
 
 /**
  * Clones a `PixelGrid`.
  * The returned instance has to be freed with `pixel_grid_dealloc`.
  */
-struct sp2_PixelGrid *sp2_pixel_grid_clone(const struct sp2_PixelGrid *this_);
+struct sp_PixelGrid *sp_pixel_grid_clone(const struct sp_PixelGrid *this_);
 
 /**
  * Deallocates a `PixelGrid`.
  *
  * Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
  */
-void sp2_pixel_grid_dealloc(struct sp2_PixelGrid *this_);
+void sp_pixel_grid_dealloc(struct sp_PixelGrid *this_);
 
 /**
  * Fills the whole `PixelGrid` with the specified value
  */
-void sp2_pixel_grid_fill(struct sp2_PixelGrid *this_, bool value);
+void sp_pixel_grid_fill(struct sp_PixelGrid *this_, bool value);
 
 /**
  * Get the current value at the specified position
  */
-bool sp2_pixel_grid_get(const struct sp2_PixelGrid *this_, size_t x, size_t y);
+bool sp_pixel_grid_get(const struct sp_PixelGrid *this_, size_t x, size_t y);
 
 /**
  * Gets the height in pixels of the `PixelGrid` instance.
  */
-size_t sp2_pixel_grid_height(const struct sp2_PixelGrid *this_);
+size_t sp_pixel_grid_height(const struct sp_PixelGrid *this_);
 
 /**
  * Loads a `PixelGrid` with the specified dimensions from the provided data.
  * The returned instance has to be freed with `pixel_grid_dealloc`.
  */
-struct sp2_PixelGrid *sp2_pixel_grid_load(size_t width,
-                                          size_t height,
-                                          const uint8_t *data,
-                                          size_t data_length);
+struct sp_PixelGrid *sp_pixel_grid_load(size_t width,
+                                        size_t height,
+                                        const uint8_t *data,
+                                        size_t data_length);
 
 /**
  * Creates a new `PixelGrid` instance.
  * The returned instance has to be freed with `pixel_grid_dealloc`.
  */
-struct sp2_PixelGrid *sp2_pixel_grid_new(size_t width, size_t height);
+struct sp_PixelGrid *sp_pixel_grid_new(size_t width, size_t height);
 
 /**
  * Sets the current value at the specified position
  */
-void sp2_pixel_grid_set(struct sp2_PixelGrid *this_,
-                        size_t x,
-                        size_t y,
-                        bool value);
+void sp_pixel_grid_set(struct sp_PixelGrid *this_,
+                       size_t x,
+                       size_t y,
+                       bool value);
 
 /**
  * Gets an unsafe reference to the data of the `PixelGrid` instance.
@@ -451,12 +443,12 @@ void sp2_pixel_grid_set(struct sp2_PixelGrid *this_,
  * Reading and writing concurrently to either the original instance or the returned data will
  * result in undefined behavior.
  */
-struct sp2_CByteSlice sp2_pixel_grid_unsafe_data_ref(struct sp2_PixelGrid *this_);
+struct sp_CByteSlice sp_pixel_grid_unsafe_data_ref(struct sp_PixelGrid *this_);
 
 /**
  * Gets the width in pixels of the `PixelGrid` instance.
  */
-size_t sp2_pixel_grid_width(const struct sp2_PixelGrid *this_);
+size_t sp_pixel_grid_width(const struct sp_PixelGrid *this_);
 
 #ifdef __cplusplus
 } // extern "C"
diff --git a/examples/lang_c/src/main.c b/examples/lang_c/src/main.c
index 7077eff..3951293 100644
--- a/examples/lang_c/src/main.c
+++ b/examples/lang_c/src/main.c
@@ -2,18 +2,18 @@
 #include "servicepoint.h"
 
 int main(void) {
-    sp2_Connection *connection = sp2_connection_open("localhost:2342");
+    sp_Connection *connection = sp_connection_open("localhost:2342");
     if (connection == NULL)
         return 1;
 
-    sp2_PixelGrid *pixels = sp2_pixel_grid_new(sp2_PIXEL_WIDTH, sp2_PIXEL_HEIGHT);
-    sp2_pixel_grid_fill(pixels, true);
+    sp_PixelGrid *pixels = sp_pixel_grid_new(sp_PIXEL_WIDTH, sp_PIXEL_HEIGHT);
+    sp_pixel_grid_fill(pixels, true);
 
-    sp2_Command *command = sp2_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
-    sp2_Packet *packet = sp2_packet_from_command(command);
-    if (!sp2_connection_send(connection, packet))
+    sp_Command *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
+    sp_Packet *packet = sp_packet_from_command(command);
+    if (!sp_connection_send(connection, packet))
         return 1;
 
-    sp2_connection_dealloc(connection);
+    sp_connection_dealloc(connection);
     return 0;
 }
diff --git a/examples/lang_cs/lang_cs.csproj b/examples/lang_cs/lang_cs.csproj
index d4fed5f..5ad0986 100644
--- a/examples/lang_cs/lang_cs.csproj
+++ b/examples/lang_cs/lang_cs.csproj
@@ -9,7 +9,7 @@
     </PropertyGroup>
 
     <ItemGroup>
-        <ProjectReference Include="..\..\servicepoint-binding-cs\src\ServicePoint.csproj"/>
+        <ProjectReference Include="../../crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj"/>
     </ItemGroup>
 
 </Project>

From d1db850fd4270603c01bd079ec43931271bf08f5 Mon Sep 17 00:00:00 2001
From: Vinzenz Schroeter <vinzenz.f.s@gmail.com>
Date: Sun, 26 May 2024 13:19:35 +0200
Subject: [PATCH 04/11] remove duplicate lock files, cargo update

---
 Cargo.lock                                |  20 +-
 crates/servicepoint/Cargo.lock            | 167 --------------
 crates/servicepoint_binding_cs/Cargo.lock | 264 ----------------------
 3 files changed, 10 insertions(+), 441 deletions(-)
 delete mode 100644 crates/servicepoint/Cargo.lock
 delete mode 100644 crates/servicepoint_binding_cs/Cargo.lock

diff --git a/Cargo.lock b/Cargo.lock
index 55cb4e5..2dc4c0b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -207,7 +207,7 @@ dependencies = [
  "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.65",
+ "syn 2.0.66",
 ]
 
 [[package]]
@@ -460,9 +460,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.83"
+version = "1.0.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
+checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
 dependencies = [
  "unicode-ident",
 ]
@@ -576,22 +576,22 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
 [[package]]
 name = "serde"
-version = "1.0.202"
+version = "1.0.203"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
+checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.202"
+version = "1.0.203"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
+checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.65",
+ "syn 2.0.66",
 ]
 
 [[package]]
@@ -657,9 +657,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.65"
+version = "2.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/crates/servicepoint/Cargo.lock b/crates/servicepoint/Cargo.lock
deleted file mode 100644
index 2807d66..0000000
--- a/crates/servicepoint/Cargo.lock
+++ /dev/null
@@ -1,167 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "adler"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-
-[[package]]
-name = "bzip2"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
-dependencies = [
- "bzip2-sys",
- "libc",
-]
-
-[[package]]
-name = "bzip2-sys"
-version = "0.1.11+1.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
-dependencies = [
- "cc",
- "libc",
- "pkg-config",
-]
-
-[[package]]
-name = "cc"
-version = "1.0.97"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
-dependencies = [
- "jobserver",
- "libc",
- "once_cell",
-]
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "crc32fast"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "flate2"
-version = "1.0.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
-dependencies = [
- "crc32fast",
- "miniz_oxide",
-]
-
-[[package]]
-name = "jobserver"
-version = "0.1.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.154"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
-
-[[package]]
-name = "log"
-version = "0.4.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
-
-[[package]]
-name = "lz4"
-version = "1.24.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1"
-dependencies = [
- "libc",
- "lz4-sys",
-]
-
-[[package]]
-name = "lz4-sys"
-version = "1.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "miniz_oxide"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
-dependencies = [
- "adler",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-
-[[package]]
-name = "pkg-config"
-version = "0.3.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
-
-[[package]]
-name = "servicepoint2"
-version = "0.2.0"
-dependencies = [
- "bzip2",
- "flate2",
- "log",
- "lz4",
- "zstd",
-]
-
-[[package]]
-name = "zstd"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a"
-dependencies = [
- "zstd-safe",
-]
-
-[[package]]
-name = "zstd-safe"
-version = "7.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a"
-dependencies = [
- "zstd-sys",
-]
-
-[[package]]
-name = "zstd-sys"
-version = "2.0.10+zstd.1.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa"
-dependencies = [
- "cc",
- "pkg-config",
-]
diff --git a/crates/servicepoint_binding_cs/Cargo.lock b/crates/servicepoint_binding_cs/Cargo.lock
deleted file mode 100644
index 572c8be..0000000
--- a/crates/servicepoint_binding_cs/Cargo.lock
+++ /dev/null
@@ -1,264 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "adler"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-
-[[package]]
-name = "aho-corasick"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "bzip2"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
-dependencies = [
- "bzip2-sys",
- "libc",
-]
-
-[[package]]
-name = "bzip2-sys"
-version = "0.1.11+1.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
-dependencies = [
- "cc",
- "libc",
- "pkg-config",
-]
-
-[[package]]
-name = "cc"
-version = "1.0.97"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
-dependencies = [
- "jobserver",
- "libc",
- "once_cell",
-]
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "crc32fast"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "csbindgen"
-version = "1.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf70eb656f35e0e6956cbde31c66431c53d8a546823489719099c71525767a9c"
-dependencies = [
- "regex",
- "syn",
-]
-
-[[package]]
-name = "flate2"
-version = "1.0.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
-dependencies = [
- "crc32fast",
- "miniz_oxide",
-]
-
-[[package]]
-name = "jobserver"
-version = "0.1.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.154"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
-
-[[package]]
-name = "log"
-version = "0.4.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
-
-[[package]]
-name = "lz4"
-version = "1.24.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1"
-dependencies = [
- "libc",
- "lz4-sys",
-]
-
-[[package]]
-name = "lz4-sys"
-version = "1.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "memchr"
-version = "2.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
-
-[[package]]
-name = "miniz_oxide"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
-dependencies = [
- "adler",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-
-[[package]]
-name = "pkg-config"
-version = "0.3.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.82"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "regex"
-version = "1.10.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-automata",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
-
-[[package]]
-name = "servicepoint-binding-cs"
-version = "0.1.0"
-dependencies = [
- "csbindgen",
- "servicepoint2",
-]
-
-[[package]]
-name = "servicepoint2"
-version = "0.2.0"
-dependencies = [
- "bzip2",
- "flate2",
- "log",
- "lz4",
- "zstd",
-]
-
-[[package]]
-name = "syn"
-version = "1.0.109"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
-
-[[package]]
-name = "zstd"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a"
-dependencies = [
- "zstd-safe",
-]
-
-[[package]]
-name = "zstd-safe"
-version = "7.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a"
-dependencies = [
- "zstd-sys",
-]
-
-[[package]]
-name = "zstd-sys"
-version = "2.0.10+zstd.1.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa"
-dependencies = [
- "cc",
- "pkg-config",
-]

From 5514f60c282b79a5df8c3e0da7187c9480823b80 Mon Sep 17 00:00:00 2001
From: Vinzenz Schroeter <vinzenz.f.s@gmail.com>
Date: Sun, 26 May 2024 13:25:36 +0200
Subject: [PATCH 05/11] exclude packages from tests so `cargo test --all` works

---
 Cargo.lock                                | 1 +
 crates/servicepoint_binding_cs/Cargo.toml | 2 ++
 examples/lang_c/Cargo.toml                | 3 +++
 3 files changed, 6 insertions(+)

diff --git a/Cargo.lock b/Cargo.lock
index 2dc4c0b..5f45fac 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -629,6 +629,7 @@ name = "servicepoint_binding_cs"
 version = "0.4.2"
 dependencies = [
  "csbindgen",
+ "servicepoint",
  "servicepoint_binding_c",
 ]
 
diff --git a/crates/servicepoint_binding_cs/Cargo.toml b/crates/servicepoint_binding_cs/Cargo.toml
index cfc909c..8e46578 100644
--- a/crates/servicepoint_binding_cs/Cargo.toml
+++ b/crates/servicepoint_binding_cs/Cargo.toml
@@ -7,9 +7,11 @@ readme = "../../README.md"
 
 [lib]
 crate-type = ["cdylib"]
+test = false
 
 [build-dependencies]
 csbindgen = "1.8.0"
 
 [dependencies]
 servicepoint_binding_c = { path = "../servicepoint_binding_c" }
+servicepoint = { path = "../servicepoint" }
diff --git a/examples/lang_c/Cargo.toml b/examples/lang_c/Cargo.toml
index 8baf474..9792416 100644
--- a/examples/lang_c/Cargo.toml
+++ b/examples/lang_c/Cargo.toml
@@ -4,6 +4,9 @@ version = "0.1.0"
 edition = "2021"
 publish = false
 
+[lib]
+test = false
+
 [build-dependencies]
 cc = "1.0"
 

From c92493fad1a79009893aef7599f7b7fb37e895e0 Mon Sep 17 00:00:00 2001
From: Vinzenz Schroeter <vinzenz.f.s@gmail.com>
Date: Sun, 26 May 2024 13:55:19 +0200
Subject: [PATCH 06/11] move examples into package (include them in published
 crate)

---
 Cargo.lock                                    | 78 +------------------
 Cargo.toml                                    |  7 +-
 crates/servicepoint/Cargo.toml                |  5 ++
 .../servicepoint/examples/announce.rs         |  7 +-
 .../servicepoint/examples/game_of_life.rs     | 13 ++--
 .../servicepoint/examples/moving_line.rs      | 14 ++--
 .../examples/random_brightness.rs             |  5 +-
 .../servicepoint/examples/wiping_clear.rs     |  5 +-
 .../examples}/lang_c/Cargo.toml               |  2 +-
 .../examples}/lang_c/Makefile                 |  0
 .../examples}/lang_c/build.rs                 |  0
 .../examples}/lang_c/include/servicepoint.h   |  0
 .../examples/lang_c/src/lib.rs                |  1 +
 .../examples}/lang_c/src/main.c               |  0
 .../examples}/lang_cs/Program.cs              |  0
 .../examples}/lang_cs/lang_cs.csproj          |  0
 examples/announce/Cargo.toml                  | 10 ---
 examples/game_of_life/Cargo.toml              | 12 ---
 examples/lang_c/src/lib.rs                    |  0
 examples/moving_line/Cargo.toml               | 10 ---
 examples/random_brightness/Cargo.toml         | 12 ---
 examples/wiping_clear/Cargo.toml              | 10 ---
 22 files changed, 26 insertions(+), 165 deletions(-)
 rename examples/announce/src/main.rs => crates/servicepoint/examples/announce.rs (89%)
 rename examples/game_of_life/src/main.rs => crates/servicepoint/examples/game_of_life.rs (90%)
 rename examples/moving_line/src/main.rs => crates/servicepoint/examples/moving_line.rs (71%)
 rename examples/random_brightness/src/main.rs => crates/servicepoint/examples/random_brightness.rs (93%)
 rename examples/wiping_clear/src/main.rs => crates/servicepoint/examples/wiping_clear.rs (88%)
 rename {examples => crates/servicepoint_binding_c/examples}/lang_c/Cargo.toml (66%)
 rename {examples => crates/servicepoint_binding_c/examples}/lang_c/Makefile (100%)
 rename {examples => crates/servicepoint_binding_c/examples}/lang_c/build.rs (100%)
 rename {examples => crates/servicepoint_binding_c/examples}/lang_c/include/servicepoint.h (100%)
 create mode 100644 crates/servicepoint_binding_c/examples/lang_c/src/lib.rs
 rename {examples => crates/servicepoint_binding_c/examples}/lang_c/src/main.c (100%)
 rename {examples => crates/servicepoint_binding_cs/examples}/lang_cs/Program.cs (100%)
 rename {examples => crates/servicepoint_binding_cs/examples}/lang_cs/lang_cs.csproj (100%)
 delete mode 100644 examples/announce/Cargo.toml
 delete mode 100644 examples/game_of_life/Cargo.toml
 delete mode 100644 examples/lang_c/src/lib.rs
 delete mode 100644 examples/moving_line/Cargo.toml
 delete mode 100644 examples/random_brightness/Cargo.toml
 delete mode 100644 examples/wiping_clear/Cargo.toml

diff --git a/Cargo.lock b/Cargo.lock
index 5f45fac..9f6627e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -17,15 +17,6 @@ dependencies = [
  "memchr",
 ]
 
-[[package]]
-name = "announce"
-version = "0.1.0"
-dependencies = [
- "clap 4.5.4",
- "env_logger",
- "servicepoint",
-]
-
 [[package]]
 name = "anstream"
 version = "0.6.14"
@@ -250,29 +241,6 @@ dependencies = [
  "syn 1.0.109",
 ]
 
-[[package]]
-name = "env_filter"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
-dependencies = [
- "log",
- "regex",
-]
-
-[[package]]
-name = "env_logger"
-version = "0.11.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
-dependencies = [
- "anstream",
- "anstyle",
- "env_filter",
- "humantime",
- "log",
-]
-
 [[package]]
 name = "errno"
 version = "0.3.9"
@@ -299,16 +267,6 @@ dependencies = [
  "miniz_oxide",
 ]
 
-[[package]]
-name = "game_of_life"
-version = "0.1.0"
-dependencies = [
- "clap 4.5.4",
- "env_logger",
- "rand",
- "servicepoint",
-]
-
 [[package]]
 name = "getrandom"
 version = "0.2.15"
@@ -347,12 +305,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "humantime"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-
 [[package]]
 name = "indexmap"
 version = "1.9.3"
@@ -425,15 +377,6 @@ dependencies = [
  "adler",
 ]
 
-[[package]]
-name = "moving_line"
-version = "0.1.0"
-dependencies = [
- "clap 4.5.4",
- "env_logger",
- "servicepoint",
-]
-
 [[package]]
 name = "once_cell"
 version = "1.19.0"
@@ -506,16 +449,6 @@ dependencies = [
  "getrandom",
 ]
 
-[[package]]
-name = "random_brightness"
-version = "0.1.0"
-dependencies = [
- "clap 4.5.4",
- "env_logger",
- "rand",
- "servicepoint",
-]
-
 [[package]]
 name = "regex"
 version = "1.10.4"
@@ -610,8 +543,10 @@ name = "servicepoint"
 version = "0.4.2"
 dependencies = [
  "bzip2",
+ "clap 4.5.4",
  "flate2",
  "log",
+ "rand",
  "rust-lzma",
  "zstd",
 ]
@@ -831,15 +766,6 @@ version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
 
-[[package]]
-name = "wiping_clear"
-version = "0.1.0"
-dependencies = [
- "clap 4.5.4",
- "env_logger",
- "servicepoint",
-]
-
 [[package]]
 name = "zstd"
 version = "0.13.1"
diff --git a/Cargo.toml b/Cargo.toml
index 9159b88..787ddeb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,10 +4,5 @@ members = [
     "crates/servicepoint",
     "crates/servicepoint_binding_c",
     "crates/servicepoint_binding_cs",
-    "examples/announce",
-    "examples/game_of_life",
-    "examples/moving_line",
-    "examples/wiping_clear",
-    "examples/random_brightness",
-    "examples/lang_c"
+    "crates/servicepoint_binding_c/examples/lang_c"
 ]
diff --git a/crates/servicepoint/Cargo.toml b/crates/servicepoint/Cargo.toml
index 9e0905b..e8b858b 100644
--- a/crates/servicepoint/Cargo.toml
+++ b/crates/servicepoint/Cargo.toml
@@ -26,3 +26,8 @@ compression_bzip2 = ["dep:bzip2"]
 compression_lzma = ["dep:rust-lzma"]
 compression_zstd = ["dep:zstd"]
 all_compressions = ["compression_zlib", "compression_bzip2", "compression_lzma", "compression_zstd"]
+
+[dev-dependencies]
+# for examples
+clap = { version = "4.5", features = ["derive"] }
+rand = "0.8"
\ No newline at end of file
diff --git a/examples/announce/src/main.rs b/crates/servicepoint/examples/announce.rs
similarity index 89%
rename from examples/announce/src/main.rs
rename to crates/servicepoint/examples/announce.rs
index a1fb81e..31d19d2 100644
--- a/examples/announce/src/main.rs
+++ b/crates/servicepoint/examples/announce.rs
@@ -14,10 +14,11 @@ struct Cli {
 
 /// example: `cargo run -- --text "Hallo,
 /// CCCB"`
-
 fn main() {
-    env_logger::init();
-    let cli = Cli::parse();
+    let mut cli = Cli::parse();
+    if cli.text.is_empty() {
+        cli.text.push("Hello, CCCB!".to_string());
+    }
 
     let connection = Connection::open(&cli.destination).unwrap();
     if cli.clear {
diff --git a/examples/game_of_life/src/main.rs b/crates/servicepoint/examples/game_of_life.rs
similarity index 90%
rename from examples/game_of_life/src/main.rs
rename to crates/servicepoint/examples/game_of_life.rs
index dae06f4..aef929e 100644
--- a/examples/game_of_life/src/main.rs
+++ b/crates/servicepoint/examples/game_of_life.rs
@@ -14,7 +14,6 @@ struct Cli {
 }
 
 fn main() {
-    env_logger::init();
     let cli = Cli::parse();
 
     let connection = Connection::open(&cli.destination).unwrap();
@@ -22,13 +21,11 @@ fn main() {
 
     loop {
         connection
-            .send(
-                Command::BitmapLinearWin(
-                    Origin(0, 0),
-                    field.clone(),
-                    CompressionCode::Lzma,
-                )
-            )
+            .send(Command::BitmapLinearWin(
+                Origin(0, 0),
+                field.clone(),
+                CompressionCode::Lzma,
+            ))
             .expect("could not send");
         thread::sleep(FRAME_PACING);
         field = iteration(field);
diff --git a/examples/moving_line/src/main.rs b/crates/servicepoint/examples/moving_line.rs
similarity index 71%
rename from examples/moving_line/src/main.rs
rename to crates/servicepoint/examples/moving_line.rs
index 5e812f7..2037146 100644
--- a/examples/moving_line/src/main.rs
+++ b/crates/servicepoint/examples/moving_line.rs
@@ -11,8 +11,6 @@ struct Cli {
 }
 
 fn main() {
-    env_logger::init();
-
     let connection = Connection::open(Cli::parse().destination).unwrap();
 
     let mut pixels = PixelGrid::max_sized();
@@ -23,13 +21,11 @@ fn main() {
             pixels.set((y + x_offset) % PIXEL_WIDTH, y, true);
         }
         connection
-            .send(
-                Command::BitmapLinearWin(
-                    Origin(0, 0),
-                    pixels.clone(),
-                    CompressionCode::Lzma,
-                )
-            )
+            .send(Command::BitmapLinearWin(
+                Origin(0, 0),
+                pixels.clone(),
+                CompressionCode::Lzma,
+            ))
             .unwrap();
         thread::sleep(FRAME_PACING);
     }
diff --git a/examples/random_brightness/src/main.rs b/crates/servicepoint/examples/random_brightness.rs
similarity index 93%
rename from examples/random_brightness/src/main.rs
rename to crates/servicepoint/examples/random_brightness.rs
index b4194e8..7e3c4e8 100644
--- a/examples/random_brightness/src/main.rs
+++ b/crates/servicepoint/examples/random_brightness.rs
@@ -17,7 +17,6 @@ struct Cli {
 }
 
 fn main() {
-    env_logger::init();
     let cli = Cli::parse();
 
     let connection = Connection::open(cli.destination).unwrap();
@@ -55,9 +54,7 @@ fn main() {
             }
         }
 
-        connection
-            .send(CharBrightness(origin, luma))
-            .unwrap();
+        connection.send(CharBrightness(origin, luma)).unwrap();
         std::thread::sleep(wait_duration);
     }
 }
diff --git a/examples/wiping_clear/src/main.rs b/crates/servicepoint/examples/wiping_clear.rs
similarity index 88%
rename from examples/wiping_clear/src/main.rs
rename to crates/servicepoint/examples/wiping_clear.rs
index 7e5d0be..3f255d8 100644
--- a/examples/wiping_clear/src/main.rs
+++ b/crates/servicepoint/examples/wiping_clear.rs
@@ -14,7 +14,6 @@ struct Cli {
 }
 
 fn main() {
-    env_logger::init();
     let cli = Cli::parse();
 
     let sleep_duration = Duration::max(
@@ -37,9 +36,7 @@ fn main() {
         let bit_vec = BitVec::from(&*pixel_data);
 
         connection
-            .send(
-                Command::BitmapLinearAnd(0, bit_vec, CompressionCode::Lzma)
-            )
+            .send(Command::BitmapLinearAnd(0, bit_vec, CompressionCode::Lzma))
             .unwrap();
         thread::sleep(sleep_duration);
     }
diff --git a/examples/lang_c/Cargo.toml b/crates/servicepoint_binding_c/examples/lang_c/Cargo.toml
similarity index 66%
rename from examples/lang_c/Cargo.toml
rename to crates/servicepoint_binding_c/examples/lang_c/Cargo.toml
index 9792416..4997310 100644
--- a/examples/lang_c/Cargo.toml
+++ b/crates/servicepoint_binding_c/examples/lang_c/Cargo.toml
@@ -11,4 +11,4 @@ test = false
 cc = "1.0"
 
 [dependencies]
-servicepoint_binding_c = { path = "../../crates/servicepoint_binding_c" }
+servicepoint_binding_c = { path = "../.." }
diff --git a/examples/lang_c/Makefile b/crates/servicepoint_binding_c/examples/lang_c/Makefile
similarity index 100%
rename from examples/lang_c/Makefile
rename to crates/servicepoint_binding_c/examples/lang_c/Makefile
diff --git a/examples/lang_c/build.rs b/crates/servicepoint_binding_c/examples/lang_c/build.rs
similarity index 100%
rename from examples/lang_c/build.rs
rename to crates/servicepoint_binding_c/examples/lang_c/build.rs
diff --git a/examples/lang_c/include/servicepoint.h b/crates/servicepoint_binding_c/examples/lang_c/include/servicepoint.h
similarity index 100%
rename from examples/lang_c/include/servicepoint.h
rename to crates/servicepoint_binding_c/examples/lang_c/include/servicepoint.h
diff --git a/crates/servicepoint_binding_c/examples/lang_c/src/lib.rs b/crates/servicepoint_binding_c/examples/lang_c/src/lib.rs
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/crates/servicepoint_binding_c/examples/lang_c/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/examples/lang_c/src/main.c b/crates/servicepoint_binding_c/examples/lang_c/src/main.c
similarity index 100%
rename from examples/lang_c/src/main.c
rename to crates/servicepoint_binding_c/examples/lang_c/src/main.c
diff --git a/examples/lang_cs/Program.cs b/crates/servicepoint_binding_cs/examples/lang_cs/Program.cs
similarity index 100%
rename from examples/lang_cs/Program.cs
rename to crates/servicepoint_binding_cs/examples/lang_cs/Program.cs
diff --git a/examples/lang_cs/lang_cs.csproj b/crates/servicepoint_binding_cs/examples/lang_cs/lang_cs.csproj
similarity index 100%
rename from examples/lang_cs/lang_cs.csproj
rename to crates/servicepoint_binding_cs/examples/lang_cs/lang_cs.csproj
diff --git a/examples/announce/Cargo.toml b/examples/announce/Cargo.toml
deleted file mode 100644
index 0b9ceed..0000000
--- a/examples/announce/Cargo.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[package]
-name = "announce"
-version = "0.1.0"
-edition = "2021"
-publish = false
-
-[dependencies]
-servicepoint = { path = "../../crates/servicepoint" }
-clap = { version = "4.5", features = ["derive"] }
-env_logger = "0.11"
diff --git a/examples/game_of_life/Cargo.toml b/examples/game_of_life/Cargo.toml
deleted file mode 100644
index df05972..0000000
--- a/examples/game_of_life/Cargo.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-name = "game_of_life"
-version = "0.1.0"
-edition = "2021"
-publish = false
-
-[dependencies]
-servicepoint = { path = "../../crates/servicepoint" }
-clap = { version = "4.5", features = ["derive"] }
-env_logger = "0.11"
-
-rand = "0.8.5"
diff --git a/examples/lang_c/src/lib.rs b/examples/lang_c/src/lib.rs
deleted file mode 100644
index e69de29..0000000
diff --git a/examples/moving_line/Cargo.toml b/examples/moving_line/Cargo.toml
deleted file mode 100644
index 23645de..0000000
--- a/examples/moving_line/Cargo.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[package]
-name = "moving_line"
-version = "0.1.0"
-edition = "2021"
-publish = false
-
-[dependencies]
-servicepoint = { path = "../../crates/servicepoint" }
-clap = { version = "4.5", features = ["derive"] }
-env_logger = "0.11"
diff --git a/examples/random_brightness/Cargo.toml b/examples/random_brightness/Cargo.toml
deleted file mode 100644
index 4330960..0000000
--- a/examples/random_brightness/Cargo.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-name = "random_brightness"
-version = "0.1.0"
-edition = "2021"
-publish = false
-
-[dependencies]
-servicepoint = { path = "../../crates/servicepoint" }
-clap = { version = "4.5", features = ["derive"] }
-env_logger = "0.11"
-
-rand = "0.8"
diff --git a/examples/wiping_clear/Cargo.toml b/examples/wiping_clear/Cargo.toml
deleted file mode 100644
index 7ba5c58..0000000
--- a/examples/wiping_clear/Cargo.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[package]
-name = "wiping_clear"
-version = "0.1.0"
-edition = "2021"
-publish = false
-
-[dependencies]
-servicepoint = { path = "../../crates/servicepoint" }
-clap = { version = "4.5", features = ["derive"] }
-env_logger = "0.11"

From 3780c2063ddffc6a85c7160b71109dd4f59db495 Mon Sep 17 00:00:00 2001
From: Vinzenz Schroeter <vinzenz.f.s@gmail.com>
Date: Sun, 26 May 2024 14:18:02 +0200
Subject: [PATCH 07/11] set version to 0.5.0

---
 Cargo.lock                                | 6 +++---
 Cargo.toml                                | 3 +++
 crates/servicepoint/Cargo.toml            | 2 +-
 crates/servicepoint_binding_c/Cargo.toml  | 4 ++--
 crates/servicepoint_binding_cs/Cargo.toml | 6 +++---
 5 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 9f6627e..e253757 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -540,7 +540,7 @@ dependencies = [
 
 [[package]]
 name = "servicepoint"
-version = "0.4.2"
+version = "0.5.0"
 dependencies = [
  "bzip2",
  "clap 4.5.4",
@@ -553,7 +553,7 @@ dependencies = [
 
 [[package]]
 name = "servicepoint_binding_c"
-version = "0.4.2"
+version = "0.5.0"
 dependencies = [
  "cbindgen",
  "servicepoint",
@@ -561,7 +561,7 @@ dependencies = [
 
 [[package]]
 name = "servicepoint_binding_cs"
-version = "0.4.2"
+version = "0.5.0"
 dependencies = [
  "csbindgen",
  "servicepoint",
diff --git a/Cargo.toml b/Cargo.toml
index 787ddeb..6379c5c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,3 +6,6 @@ members = [
     "crates/servicepoint_binding_cs",
     "crates/servicepoint_binding_c/examples/lang_c"
 ]
+
+[workspace.package]
+version = "0.5.0"
diff --git a/crates/servicepoint/Cargo.toml b/crates/servicepoint/Cargo.toml
index e8b858b..4b24f07 100644
--- a/crates/servicepoint/Cargo.toml
+++ b/crates/servicepoint/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "servicepoint"
-version = "0.4.2"
+version.workspace = true
 publish = true
 edition = "2021"
 license = "GPL-3.0-or-later"
diff --git a/crates/servicepoint_binding_c/Cargo.toml b/crates/servicepoint_binding_c/Cargo.toml
index d47ccde..cc938d1 100644
--- a/crates/servicepoint_binding_c/Cargo.toml
+++ b/crates/servicepoint_binding_c/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "servicepoint_binding_c"
-version = "0.4.2"
+version.workspace = true
 publish = false
 edition = "2021"
 license = "GPL-3.0-or-later"
@@ -17,6 +17,6 @@ crate-type = ["staticlib", "cdylib", "rlib"]
 cbindgen = "0.26.0"
 
 [dependencies.servicepoint]
-version = "0.4.2"
+version = "0.5.0"
 path = "../servicepoint"
 features = ["all_compressions"]
diff --git a/crates/servicepoint_binding_cs/Cargo.toml b/crates/servicepoint_binding_cs/Cargo.toml
index 8e46578..f43abe2 100644
--- a/crates/servicepoint_binding_cs/Cargo.toml
+++ b/crates/servicepoint_binding_cs/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "servicepoint_binding_cs"
-version = "0.4.2"
+version.workspace = true
 edition = "2021"
 publish = false
 readme = "../../README.md"
@@ -13,5 +13,5 @@ test = false
 csbindgen = "1.8.0"
 
 [dependencies]
-servicepoint_binding_c = { path = "../servicepoint_binding_c" }
-servicepoint = { path = "../servicepoint" }
+servicepoint_binding_c = { version = "0.5.0", path = "../servicepoint_binding_c" }
+servicepoint = { version = "0.5.0", path = "../servicepoint" }

From ccbba9ad838e6e05ee7c4e14eb38665e41244c62 Mon Sep 17 00:00:00 2001
From: Vinzenz Schroeter <vinzenz.f.s@gmail.com>
Date: Sun, 26 May 2024 14:53:26 +0200
Subject: [PATCH 08/11] split README

---
 README.md                                     | 155 ++----------------
 crates/servicepoint/Cargo.toml                |   2 +-
 crates/servicepoint/README.md                 |  54 ++++++
 crates/servicepoint_binding_c/Cargo.toml      |   2 +-
 crates/servicepoint_binding_c/README.md       |  63 +++++++
 crates/servicepoint_binding_cs/Cargo.toml     |   2 +-
 crates/servicepoint_binding_cs/README.md      |  65 ++++++++
 .../ServicePoint/ServicePoint.csproj          |   2 +-
 8 files changed, 199 insertions(+), 146 deletions(-)
 create mode 100644 crates/servicepoint/README.md
 create mode 100644 crates/servicepoint_binding_c/README.md
 create mode 100644 crates/servicepoint_binding_cs/README.md

diff --git a/README.md b/README.md
index b422c20..bae2ed9 100644
--- a/README.md
+++ b/README.md
@@ -1,160 +1,31 @@
 # servicepoint
 
-[![crates.io](https://img.shields.io/crates/v/servicepoint.svg)](https://crates.io/crates/servicepoint)
-[![Crates.io Total Downloads](https://img.shields.io/crates/d/servicepoint)](https://crates.io/crates/servicepoint)
-[![docs.rs](https://img.shields.io/docsrs/servicepoint)](https://docs.rs/servicepoint/latest/servicepoint/)
-[![GPLv3 licensed](https://img.shields.io/crates/l/servicepoint)](./LICENSE)
-
 In [CCCB](https://berlin.ccc.de/), there is a big pixel matrix hanging on the wall. It is called  "Service Point
 Display" or "Airport Display".
-This repository contains a library for parsing, encoding and sending packets to this display via UDP.
+This repository contains a library for parsing, encoding and sending packets to this display via UDP in multiple
+programming languages.
 
-## Note on stability
+Take a look at the contained crates for language specific information:
 
-This library is still in early development.
-You can absolutely use it, and it works, but expect minor breaking changes with every version bump.
-Please specify the full version including patch in your Cargo.toml until 1.0 is released.
-
-Expect bugs and/or missing features in the language bindings for now. If you need something specific, open an issue or a pull request.
-
-## Rust
-
-This is where the library works the best.
-Any API usage accepted by the compiler in a safe context is either safe or buggy (issues welcome)
-
-```bash
-cargo add servicepoint
-```
-
-```rust
-fn main() {
-    // establish connection
-    let connection = servicepoint::Connection::open("172.23.42.29:2342")
-        .expect("connection failed");
-
-    // clear screen content
-    connection.send(servicepoint::Command::Clear.into())
-        .expect("send failed");
-}
-```
-
-More examples are available in the repository folder and in the [Projects using the library]() section
-
-## C / C++
-
-The lowest common denominator. Things to keep in mind:
-
-- This is a chainsaw. You will cut your leg.
-- function names are: `sp2_` \<struct_name\> \<rust name\>.
-- Use the rust documentation.
-- Instances get consumed in the same way they do when writing rust / C# code. Do not use an instance after an (implicit!) free.
-- Option<T> or Result<T, E> turn into nullable return values - check for NULL!
-- There are no specifics for C++ here yet. You might get a nicer header when generating directly for C++, but it should be usable.
-- Reading and writing to instances concurrently is not safe. Only reading concurrently is safe.
-
-```c++
-#include <stdio.h>
-#include "servicepoint.h"
-
-int main(void) {
-    sp2_Connection *connection = sp2_connection_open("localhost:2342");
-    if (connection == NULL)
-        return 1;
-
-    sp2_PixelGrid *pixels = sp2_pixel_grid_new(sp2_PIXEL_WIDTH, sp2_PIXEL_HEIGHT);
-    sp2_pixel_grid_fill(pixels, true);
-
-    sp2_Command *command = sp2_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
-    sp2_Packet *packet = sp2_packet_from_command(command);
-    if (!sp2_connection_send(connection, packet))
-        return 1;
-
-    sp2_connection_dealloc(connection);
-    return 0;
-}
-```
-
-## C# / F#
-
-Uses C bindings internally to provide a similar API to rust. Things to keep in mind:
-
-- You will get a `NullPointerException` when trying to call a method where the native instance has been consumed already (e.g. when `Send`ing a command instance twice). Send a clone instead of the original if you want to keep using it.
-- Some lower-level APIs _will_ panic in native code when used improperly.
-  Example: manipulating the `Span<byte>` of an object after freeing the instance.
-- C# specifics are documented in the library. Use the rust documentation for everything else. Naming and semantics are the same apart from CamelCase instead of kebab_case.
-- You will only get rust backtraces in debug builds of the native code.
-- F# is not explicitly tested. If there are usability or functionality problems, please open an issue.
-- Reading and writing to instances concurrently is not safe. Only reading concurrently is safe.
-
-```csharp
-using ServicePoint;
-
-// using statement calls Dispose() on scope exit, which frees unmanaged instances
-using var connection = Connection.Open("127.0.0.1:2342");
-using var pixels = PixelGrid.New(Constants.PixelWidth, Constants.PixelHeight);
-
-while (true)
-{
-    pixels.Fill(true);
-    connection.Send(Command.BitmapLinearWin(0, 0, pixels.Clone()));
-    Thread.Sleep(5000);
-
-    pixels.Fill(false);
-    connection.Send(Command.BitmapLinearWin(0, 0, pixels.Clone()));
-    Thread.Sleep(5000);
-}
-```
-
-### Installation
-
-NuGet packages are not a good way to distribute native projects ([relevant issue](https://github.com/dotnet/sdk/issues/33845)).
-Because of that, there is no NuGet package you can use directly.
-Including this repository as a submodule and building from source is the recommended way of using the library.
-
-```bash
-git submodule add https://github.com/kaesaecracker/servicepoint.git
-git commit -m "add servicepoint submodule"
-```
-
-You can now reference `servicepoint-bindings-cs/src/ServicePoint.csproj` in your project.
-The rust library will automatically be built.
-
-Please provide more information in the form of an issue if you need the build to copy a different library file for your platform.
-
-### Installation
-
-Copy the header to your project and compile against.
-
-You have the choice of linking statically (recommended) or dynamically.
-- The C example shows how to link statically against the `staticlib` variant.
-- When linked dynamically, you have to provide the `cdylib` at runtime in the _same_ version, as there are no API/ABI guarantees yet.
-
-## Features
-
-This library has multiple compression libraries as optional dependencies.
-If you do not need compression/decompression support you can disable those features.
-In the likely case you only need one of them, you can include that one specifically.
-
-```toml
-[dependencies.servicepoint]
-git = "https://github.com/kaesaecracker/servicepoint.git"
-default-features = false
-features = ["compression-bz"]
-```
-
-Language bindings will not know which features are available and may fail at runtime.
-It is recommended to include all features for builds used outside of rust.
+| Language | Readme                                                              |
+|----------|---------------------------------------------------------------------|
+| Rust     | [servicepoint](crates/servicepoint/README.md)                       |
+| C / C++  | [servicepoint_binding_c](crates/servicepoint_binding_c/README.md)   |
+| C# / F#  | [servicepoint_binding_cs](crates/servicepoint_binding_cs/README.md) | 
 
 ## Projects using the library
 
-- screen simulator (rust): https://github.com/kaesaecracker/pixel-receiver-rs
+- screen simulator (rust): https://github.com/kaesaecracker/servicepoint-simulator
 - tanks game (C#): https://github.com/kaesaecracker/cccb-tanks-cs
+- cellular automata slideshow (rust): https://github.com/kaesaecracker/servicepoint-life
 
 To add yourself to the list, open a pull request.
 
 ## Where is servicepoint1?
 
-This library is a spiritual mix of a not-yet-working rust library called `servicepoint` and a bunch of working but also unfinished C# code. Because most of the API concept and a bunch of code is taken from the rust library, the result is called `servicepoint`.
+This library is a spiritual mix of a not-yet-working rust library called `servicepoint` and a bunch of working but also
+unfinished C# code. Because most of the API concept and a bunch of code is taken from the rust library, the result is
+called `servicepoint`.
 
 ## Contributing
 
diff --git a/crates/servicepoint/Cargo.toml b/crates/servicepoint/Cargo.toml
index 4b24f07..6ae0b0e 100644
--- a/crates/servicepoint/Cargo.toml
+++ b/crates/servicepoint/Cargo.toml
@@ -7,7 +7,7 @@ license = "GPL-3.0-or-later"
 description = "A rust library for the CCCB Service Point Display."
 homepage = "https://docs.rs/crate/servicepoint"
 repository = "https://github.com/cccb/servicepoint"
-readme = "../../README.md"
+readme = "README.md"
 
 [lib]
 crate-type = ["rlib"]
diff --git a/crates/servicepoint/README.md b/crates/servicepoint/README.md
new file mode 100644
index 0000000..9d7064b
--- /dev/null
+++ b/crates/servicepoint/README.md
@@ -0,0 +1,54 @@
+# servicepoint
+
+[![crates.io](https://img.shields.io/crates/v/servicepoint.svg)](https://crates.io/crates/servicepoint)
+[![Crates.io Total Downloads](https://img.shields.io/crates/d/servicepoint)](https://crates.io/crates/servicepoint)
+[![docs.rs](https://img.shields.io/docsrs/servicepoint)](https://docs.rs/servicepoint/latest/servicepoint/)
+[![GPLv3 licensed](https://img.shields.io/crates/l/servicepoint)](../../LICENSE)
+
+In [CCCB](https://berlin.ccc.de/), there is a big pixel matrix hanging on the wall. It is called  "Service Point
+Display" or "Airport Display".
+This crate contains a library for parsing, encoding and sending packets to this display via UDP.
+
+## Examples
+
+```rust
+fn main() {
+    // establish connection
+    let connection = servicepoint::Connection::open("172.23.42.29:2342")
+        .expect("connection failed");
+
+    // clear screen content
+    connection.send(servicepoint::Command::Clear.into())
+        .expect("send failed");
+}
+```
+
+More examples are available in the crate. 
+Execute `cargo run --example` for a list of available examples and `cargo run --example <name>` to run one.
+
+## Note on stability
+
+This library is still in early development.
+You can absolutely use it, and it works, but expect minor breaking changes with every version bump.
+Please specify the full version including patch in your Cargo.toml until 1.0 is released.
+
+## Installation
+
+```bash
+cargo add servicepoint
+```
+
+## Features
+
+This library has multiple compression libraries as optional dependencies.
+If you do not need compression/decompression support you can disable those features.
+In the likely case you only need one of them, you can include that one specifically.
+
+```toml
+[dependencies]
+servicepoint = { version = "0.5.0", default-features = false, features = ["compression-bz"] }
+```
+
+## Everything else
+
+Look at the main project [README](https://github.com/cccb/servicepoint/blob/main/README.md) for further information.
diff --git a/crates/servicepoint_binding_c/Cargo.toml b/crates/servicepoint_binding_c/Cargo.toml
index cc938d1..4146255 100644
--- a/crates/servicepoint_binding_c/Cargo.toml
+++ b/crates/servicepoint_binding_c/Cargo.toml
@@ -7,7 +7,7 @@ license = "GPL-3.0-or-later"
 description = "C bindings for the servicepoint crate."
 homepage = "https://docs.rs/crate/servicepoint"
 repository = "https://github.com/cccb/servicepoint"
-readme = "../../README.md"
+readme = "README.md"
 links = "servicepoint"
 
 [lib]
diff --git a/crates/servicepoint_binding_c/README.md b/crates/servicepoint_binding_c/README.md
new file mode 100644
index 0000000..1a86753
--- /dev/null
+++ b/crates/servicepoint_binding_c/README.md
@@ -0,0 +1,63 @@
+# servicepoint_binding_c
+
+[![crates.io](https://img.shields.io/crates/v/servicepoint_binding_c.svg)](https://crates.io/crates/servicepoint)
+[![Crates.io Total Downloads](https://img.shields.io/crates/d/servicepoint_binding_c)](https://crates.io/crates/servicepoint)
+[![docs.rs](https://img.shields.io/docsrs/servicepoint_binding_c)](https://docs.rs/servicepoint/latest/servicepoint/)
+[![GPLv3 licensed](https://img.shields.io/crates/l/servicepoint_binding_c)](../../LICENSE)
+
+In [CCCB](https://berlin.ccc.de/), there is a big pixel matrix hanging on the wall. It is called  "Service Point
+Display" or "Airport Display".
+This crate contains C bindings for the `servicepoint` library, enabling users to parse, encode and send packets to this display via UDP.
+
+## Examples
+
+```c++
+#include <stdio.h>
+#include "servicepoint.h"
+
+int main(void) {
+    sp2_Connection *connection = sp2_connection_open("localhost:2342");
+    if (connection == NULL)
+        return 1;
+
+    sp2_PixelGrid *pixels = sp2_pixel_grid_new(sp2_PIXEL_WIDTH, sp2_PIXEL_HEIGHT);
+    sp2_pixel_grid_fill(pixels, true);
+
+    sp2_Command *command = sp2_command_bitmap_linear_win(0, 0, pixels, Uncompressed);
+    sp2_Packet *packet = sp2_packet_from_command(command);
+    if (!sp2_connection_send(connection, packet))
+        return 1;
+
+    sp2_connection_dealloc(connection);
+    return 0;
+}
+```
+
+A full example including Makefile is available as part of this crate.
+
+## Note on stability
+
+This library is still in early development.
+You can absolutely use it, and it works, but expect minor breaking changes with every version bump.
+Please specify the full version including patch in your Cargo.toml until 1.0 is released.
+
+## Installation
+
+Copy the header to your project and compile against.
+
+You have the choice of linking statically (recommended) or dynamically.
+- The C example shows how to link statically against the `staticlib` variant.
+- When linked dynamically, you have to provide the `cdylib` at runtime in the _same_ version, as there are no API/ABI guarantees yet.
+
+## Notes on differences to rust library
+
+- function names are: `sp2_` \<struct_name\> \<rust name\>.
+- Use the rust documentation.
+- Instances get consumed in the same way they do when writing rust / C# code. Do not use an instance after an (implicit!) free.
+- Option<T> or Result<T, E> turn into nullable return values - check for NULL!
+- There are no specifics for C++ here yet. You might get a nicer header when generating directly for C++, but it should be usable.
+- Reading and writing to instances concurrently is not safe. Only reading concurrently is safe.
+
+## Everything else
+
+Look at the main project [README](https://github.com/cccb/servicepoint/blob/main/README.md) for further information.
diff --git a/crates/servicepoint_binding_cs/Cargo.toml b/crates/servicepoint_binding_cs/Cargo.toml
index f43abe2..7282c1d 100644
--- a/crates/servicepoint_binding_cs/Cargo.toml
+++ b/crates/servicepoint_binding_cs/Cargo.toml
@@ -3,7 +3,7 @@ name = "servicepoint_binding_cs"
 version.workspace = true
 edition = "2021"
 publish = false
-readme = "../../README.md"
+readme = "README.md"
 
 [lib]
 crate-type = ["cdylib"]
diff --git a/crates/servicepoint_binding_cs/README.md b/crates/servicepoint_binding_cs/README.md
new file mode 100644
index 0000000..1248af7
--- /dev/null
+++ b/crates/servicepoint_binding_cs/README.md
@@ -0,0 +1,65 @@
+# ServicePoint
+
+In [CCCB](https://berlin.ccc.de/), there is a big pixel matrix hanging on the wall. It is called  "Service Point
+Display" or "Airport Display".
+This crate contains C# bindings for the `servicepoint` library, enabling users to parse, encode and send packets to this display via UDP.
+
+## Examples
+
+```csharp
+using ServicePoint;
+
+// using statement calls Dispose() on scope exit, which frees unmanaged instances
+using var connection = Connection.Open("127.0.0.1:2342");
+using var pixels = PixelGrid.New(Constants.PixelWidth, Constants.PixelHeight);
+
+while (true)
+{
+    pixels.Fill(true);
+    connection.Send(Command.BitmapLinearWin(0, 0, pixels.Clone()));
+    Thread.Sleep(5000);
+
+    pixels.Fill(false);
+    connection.Send(Command.BitmapLinearWin(0, 0, pixels.Clone()));
+    Thread.Sleep(5000);
+}
+```
+
+A full example including project files is available as part of this crate.
+
+## Note on stability
+
+This library is still in early development.
+You can absolutely use it, and it works, but expect minor breaking changes with every version bump.
+
+## Installation
+
+NuGet packages are not a good way to distribute native projects ([relevant issue](https://github.com/dotnet/sdk/issues/33845)).
+Because of that, there is no NuGet package you can use directly.
+Including this repository as a submodule and building from source is the recommended way of using the library.
+
+```bash
+git submodule add https://github.com/kaesaecracker/servicepoint.git
+git commit -m "add servicepoint submodule"
+```
+
+You can now reference `servicepoint-bindings-cs/src/ServicePoint.csproj` in your project.
+The rust library will automatically be built.
+
+Please provide more information in the form of an issue if you need the build to copy a different library file for your platform.
+
+## Notes on differences to rust library
+
+Uses C bindings internally to provide a similar API to rust. Things to keep in mind:
+
+- You will get a `NullPointerException` when trying to call a method where the native instance has been consumed already (e.g. when `Send`ing a command instance twice). Send a clone instead of the original if you want to keep using it.
+- Some lower-level APIs _will_ panic in native code when used improperly.
+  Example: manipulating the `Span<byte>` of an object after freeing the instance.
+- C# specifics are documented in the library. Use the rust documentation for everything else. Naming and semantics are the same apart from CamelCase instead of kebab_case.
+- You will only get rust backtraces in debug builds of the native code.
+- F# is not explicitly tested. If there are usability or functionality problems, please open an issue.
+- Reading and writing to instances concurrently is not safe. Only reading concurrently is safe.
+
+## Everything else
+
+Look at the main project [README](https://github.com/cccb/servicepoint/blob/main/README.md) for further information.
diff --git a/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj b/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj
index e82c589..30778d0 100644
--- a/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj
+++ b/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj
@@ -56,7 +56,7 @@
 
     <ItemGroup>
         <!-- include link to source code at revision -->
-        <None Include="../../../README.md" Pack="true" PackagePath="\"/>
+        <None Include="../README.md" Pack="true" PackagePath="\"/>
         <!-- add README.md to package -->
         <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
     </ItemGroup>

From 8bf1452e31c4dc14635c783987288111ebe5dce3 Mon Sep 17 00:00:00 2001
From: Vinzenz Schroeter <vinzenz.f.s@gmail.com>
Date: Sun, 26 May 2024 14:58:05 +0200
Subject: [PATCH 09/11] fix c# example

---
 crates/servicepoint_binding_cs/ServicePoint.sln                 | 2 +-
 crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj | 2 +-
 crates/servicepoint_binding_cs/examples/lang_cs/lang_cs.csproj  | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/crates/servicepoint_binding_cs/ServicePoint.sln b/crates/servicepoint_binding_cs/ServicePoint.sln
index 29b9889..3d278f9 100644
--- a/crates/servicepoint_binding_cs/ServicePoint.sln
+++ b/crates/servicepoint_binding_cs/ServicePoint.sln
@@ -2,7 +2,7 @@
 Microsoft Visual Studio Solution File, Format Version 12.00
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint", "ServicePoint/ServicePoint.csproj", "{70EFFA3F-012A-4518-9627-466BEAE4252E}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lang-cs", "../../examples/lang_cs/lang_cs.csproj", "{DA3B8B6E-993A-47DA-844B-F92AF520FF59}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lang-cs", "examples/lang_cs/lang_cs.csproj", "{DA3B8B6E-993A-47DA-844B-F92AF520FF59}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj b/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj
index 30778d0..d871fcd 100644
--- a/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj
+++ b/crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj
@@ -12,7 +12,7 @@
 
     <PropertyGroup>
         <PackageId>ServicePoint</PackageId>
-        <Version>0.3.0</Version>
+        <Version>0.5.0</Version>
         <Authors>Repository Authors</Authors>
         <Company>None</Company>
         <Product>ServicePoint</Product>
diff --git a/crates/servicepoint_binding_cs/examples/lang_cs/lang_cs.csproj b/crates/servicepoint_binding_cs/examples/lang_cs/lang_cs.csproj
index 5ad0986..e83a385 100644
--- a/crates/servicepoint_binding_cs/examples/lang_cs/lang_cs.csproj
+++ b/crates/servicepoint_binding_cs/examples/lang_cs/lang_cs.csproj
@@ -9,7 +9,7 @@
     </PropertyGroup>
 
     <ItemGroup>
-        <ProjectReference Include="../../crates/servicepoint_binding_cs/ServicePoint/ServicePoint.csproj"/>
+        <ProjectReference Include="../../ServicePoint/ServicePoint.csproj"/>
     </ItemGroup>
 
 </Project>

From 868988cc8dbde0660bdd9341e9c93f02eaae8b6c Mon Sep 17 00:00:00 2001
From: Vinzenz Schroeter <vinzenz.f.s@gmail.com>
Date: Sun, 26 May 2024 15:08:41 +0200
Subject: [PATCH 10/11] add information about display hardware

---
 README.md | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/README.md b/README.md
index bae2ed9..bebe41a 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,50 @@ Take a look at the contained crates for language specific information:
 
 To add yourself to the list, open a pull request.
 
+## About the display
+
+- Resolution: 352x160=56,320 pixels
+- Pixels are grouped into 44x20=880 tiles (8x8=64 pixels each)
+- Smallest addressable unit: row of pixels inside of a tile (8 pixels = 1 byte)
+- The brightness can only be set per tile
+- Screen content can be changed using a simple UDP protocol
+- Between each row of tiles, there is a gap of around 4 pixels size. This gap changes the aspect ratio of the display.
+
+### Binary format
+
+A UDP package sent to the display has a header size of 10 bytes.
+Each header value has a size of two bytes (unsigned 16 bit integer).
+Depending on the command, there can be a payload following the header.
+
+The commands are implemented in DisplayCommands.
+
+To change screen contents, these commands are the most relevant:
+1. Clear screen
+    - command: `0x0002`
+    - (rest does not matter)
+2. Send CP437 data: render specified text into rectangular region
+    - command: `0x0003`
+    - top left tile x
+    - top left tile y
+    - width in tiles
+    - height in tiles
+    - payload: (width in tiles * height in tiles) bytes
+        - 1 byte = 1 character
+        - each character is rendered into one tile (mono-spaced)
+        - characters are encoded using code page 437
+3. Send bitmap window: set pixel states for a rectangular region
+    - command: `0x0013`
+    - top left tile x
+    - top left _pixel_ y
+    - width in tiles
+    - height in _pixels_
+    - payload: (width in tiles * height in pixels) bytes
+        - network byte order
+        - 1 bit = 1 pixel
+
+There are other commands implemented as well, e.g. for changing the brightness.
+
+
 ## Where is servicepoint1?
 
 This library is a spiritual mix of a not-yet-working rust library called `servicepoint` and a bunch of working but also

From 82392283e1d826a33874c5e45edcc28e013b80ae Mon Sep 17 00:00:00 2001
From: Vinzenz Schroeter <vinzenz.f.s@gmail.com>
Date: Sun, 26 May 2024 15:15:31 +0200
Subject: [PATCH 11/11] update README

---
 README.md | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md
index bebe41a..c355df0 100644
--- a/README.md
+++ b/README.md
@@ -15,9 +15,9 @@ Take a look at the contained crates for language specific information:
 
 ## Projects using the library
 
-- screen simulator (rust): https://github.com/kaesaecracker/servicepoint-simulator
-- tanks game (C#): https://github.com/kaesaecracker/cccb-tanks-cs
-- cellular automata slideshow (rust): https://github.com/kaesaecracker/servicepoint-life
+- screen simulator (rust): [servicepoint-simulator](https://github.com/kaesaecracker/servicepoint-simulator)
+- tanks game (C#): [servicepoint-tanks](https://github.com/kaesaecracker/cccb-tanks-cs)
+- cellular automata slideshow (rust): [servicepoint-life](https://github.com/kaesaecracker/servicepoint-life)
 
 To add yourself to the list, open a pull request.
 
@@ -39,6 +39,7 @@ Depending on the command, there can be a payload following the header.
 The commands are implemented in DisplayCommands.
 
 To change screen contents, these commands are the most relevant:
+
 1. Clear screen
     - command: `0x0002`
     - (rest does not matter)
@@ -64,12 +65,9 @@ To change screen contents, these commands are the most relevant:
 
 There are other commands implemented as well, e.g. for changing the brightness.
 
+## What happened to servicepoint2?
 
-## Where is servicepoint1?
-
-This library is a spiritual mix of a not-yet-working rust library called `servicepoint` and a bunch of working but also
-unfinished C# code. Because most of the API concept and a bunch of code is taken from the rust library, the result is
-called `servicepoint`.
+After `servicepoint2` has been merged into `servicepoint`, `servicepoint2` will not continue to get any updates.
 
 ## Contributing