{"id":51421114,"url":"https://github.com/firechip/cobs_codec_kt","last_synced_at":"2026-07-05T00:01:44.931Z","repository":{"id":369271098,"uuid":"1289115012","full_name":"firechip/cobs_codec_kt","owner":"firechip","description":"Pure-Kotlin Consistent Overhead Byte Stuffing (COBS) and COBS/R for Android, packaged as an .aar. Kotlin sibling of the Dart cobs_codec package.","archived":false,"fork":false,"pushed_at":"2026-07-04T12:50:56.000Z","size":132,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-04T13:10:20.882Z","etag":null,"topics":["aar","android","byte-stuffing","cobs","cobs-r","embedded","framing","kotlin","serial","uart"],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/firechip.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-04T11:03:53.000Z","updated_at":"2026-07-04T12:50:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/firechip/cobs_codec_kt","commit_stats":null,"previous_names":["firechip/cobs_codec_kt"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/firechip/cobs_codec_kt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firechip%2Fcobs_codec_kt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firechip%2Fcobs_codec_kt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firechip%2Fcobs_codec_kt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firechip%2Fcobs_codec_kt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/firechip","download_url":"https://codeload.github.com/firechip/cobs_codec_kt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firechip%2Fcobs_codec_kt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35139194,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aar","android","byte-stuffing","cobs","cobs-r","embedded","framing","kotlin","serial","uart"],"created_at":"2026-07-05T00:01:44.225Z","updated_at":"2026-07-05T00:01:44.915Z","avatar_url":"https://github.com/firechip.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cobs_codec\n\n_Kotlin / Android edition — Maven artifact `dev.firechip:cobs_codec`, repository\n[`cobs_codec_kt`](https://github.com/firechip/cobs_codec_kt) (the `_kt` suffix is\njust the repo slug)._\n\n[![CI](https://github.com/firechip/cobs_codec_kt/actions/workflows/ci.yml/badge.svg)](https://github.com/firechip/cobs_codec_kt/actions/workflows/ci.yml)\n[![Release](https://img.shields.io/github/v/release/firechip/cobs_codec_kt?sort=semver)](https://github.com/firechip/cobs_codec_kt/releases)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\nPure-Kotlin **Consistent Overhead Byte Stuffing (COBS)** and **COBS/R** for\nAndroid, distributed as an `.aar`. It is the Kotlin/Android member of the\nFirechip COBS family (alongside the Dart\n[`cobs_codec`](https://pub.dev/packages/cobs_codec) on pub.dev) and produces\nbyte-identical output (validated against the shared conformance vectors).\n\nCOBS encodes an arbitrary `ByteArray` into one that contains no zero (`0x00`)\nbytes, at a small, predictable cost (at most one extra byte per 254 bytes, plus\none). That lets a single `0x00` reliably delimit packets on a byte stream such\nas a serial/UART, USB, or BLE link.\n\n## Features\n\n- **Basic COBS** and **COBS/R (Reduced)** encode/decode (`Cobs`, `Cobsr`).\n- **Configurable sentinel** — encode/decode (both COBS and COBS/R) against any\n  delimiter byte instead of `0x00`, via `encodeWithSentinel` / `decodeWithSentinel`.\n  The encoded output never contains the sentinel byte, so a non-`0x00` byte can\n  delimit frames; a `sentinel` of `0` is byte-for-byte identical to the plain\n  codec.\n- **In-place decode** (basic COBS) — `Cobs.decodeInPlace` decodes within the same\n  buffer with no second allocation, returning the decoded length. COBS never\n  expands on decode, so the decoded bytes occupy the front of the buffer.\n- **Stream framing** for delimiter-framed links: `CobsFraming.frame` /\n  `unframe`, and the incremental `CobsStreamDecoder` (reassembles packets across\n  arbitrary chunk boundaries, with a `maxFrameLength` guard). Each takes a\n  `sentinel` byte (default `0x00`) so frames can be delimited by any chosen byte.\n- **`java.io` stream adapters** — `CobsFramedOutputStream.writeFrame` /\n  `CobsFramedInputStream.readFrame` (plus `frames()` as a `Sequence`) wrap any\n  `OutputStream` / `InputStream` to write and read self-delimiting frames. They\n  use only `java.io`, so they add no dependency.\n- **Coroutines `Flow` hook** — `Flow\u003cByteArray\u003e.cobsFrames()` reassembles a flow\n  of raw chunks into a flow of decoded packets. `kotlinx-coroutines` is a\n  `compileOnly` dependency, so the published artifact stays free of any runtime\n  dependency; the extension is available to consumers who already use coroutines.\n- **Zero dependencies**, pure Kotlin, no Android framework APIs in the logic.\n  `minSdk 21`, `compileSdk 35`.\n\n## Install\n\n### Gradle (GitHub Packages)\n\nThe library is published to the GitHub Packages Maven registry as\n`dev.firechip:cobs_codec`. Add the repository and the dependency:\n\n```kotlin\nrepositories {\n    maven {\n        url = uri(\"https://maven.pkg.github.com/firechip/cobs_codec_kt\")\n        credentials {\n            username = providers.gradleProperty(\"gpr.user\").orNull\n                ?: System.getenv(\"GITHUB_ACTOR\")\n            password = providers.gradleProperty(\"gpr.key\").orNull\n                ?: System.getenv(\"GITHUB_TOKEN\")\n        }\n    }\n}\n\ndependencies {\n    implementation(\"dev.firechip:cobs_codec:1.1.0\")\n}\n```\n\n\u003e GitHub Packages requires authentication even for public packages. Use a GitHub\n\u003e [personal access token](https://github.com/settings/tokens) with the\n\u003e `read:packages` scope, set as `gpr.user` / `gpr.key` in\n\u003e `~/.gradle/gradle.properties` (or the `GITHUB_ACTOR` / `GITHUB_TOKEN`\n\u003e environment variables).\n\n### Direct `.aar` download\n\nAlternatively, the `.aar` is attached to every\n[GitHub release](https://github.com/firechip/cobs_codec_kt/releases) and needs no\nauthentication:\n\n```kotlin\ndependencies {\n    implementation(files(\"libs/cobs_codec-1.1.0.aar\"))\n}\n```\n\n## Usage\n\n```kotlin\nimport dev.firechip.cobs.Cobs\nimport dev.firechip.cobs.Cobsr\nimport dev.firechip.cobs.CobsFraming\nimport dev.firechip.cobs.CobsStreamDecoder\n\n// Encode / decode a single packet.\nval encoded = Cobs.encode(byteArrayOf(0x11, 0x00, 0x22)) // [0x02,0x11,0x02,0x22]\nval decoded = Cobs.decode(encoded)                       // [0x11,0x00,0x22]\n\n// COBS/R often avoids the trailing overhead byte for small messages.\nCobsr.encode(\"12345\".toByteArray())                      // \"51234\" bytes\n\n// Frame a packet for a delimited link, then split a buffer back into packets.\nval frame = CobsFraming.frame(byteArrayOf(0x11, 0x00, 0x22)) // ... trailing 0x00\nval packets = CobsFraming.unframe(frame)\n\n// Decode a live serial stream whose chunks do not align with frame boundaries.\nval rx = CobsStreamDecoder(maxFrameLength = 4096)\nserialPort.onBytes { chunk -\u003e rx.feed(chunk).forEach(::handlePacket) }\n\n// Configurable sentinel: encode/decode against any delimiter byte, not just 0x00.\n// The output never contains the sentinel, so it can delimit frames instead of 0x00.\n// A Byte literal above 0x7F needs `.toByte()`, e.g. 0xAA.toByte().\nval s = 0xAA.toByte()\nval stuffed = Cobs.encodeWithSentinel(byteArrayOf(0x11, 0x00, 0x22), s) // [0xA8,0xBB,0xA8,0x88], no 0xAA\nCobs.decodeWithSentinel(stuffed, s)                                     // [0x11,0x00,0x22]\nCobsr.encodeWithSentinel(byteArrayOf(0x11, 0x00, 0x22), s)             // [0xA8,0xBB,0x88], COBS/R variant\n\n// In-place decode (basic COBS only): no second allocation; returns the decoded length.\nval buf = Cobs.encode(byteArrayOf(0x11, 0x00, 0x22)) // [0x02,0x11,0x02,0x22]\nval n = Cobs.decodeInPlace(buf)                      // n == 3; buf.copyOf(n) == [0x11,0x00,0x22]\n// Cobs.decodeInPlace(buf, s) does the same for sentinel-encoded data.\n\n// Sentinel-aware framing: frame/unframe and the stream decoder all take a sentinel.\nval framed = CobsFraming.frame(byteArrayOf(0x11, 0x00, 0x22), sentinel = s) // ...trailing 0xAA\nCobsFraming.unframe(framed, sentinel = s)                                   // [[0x11,0x00,0x22]]\nval rxAA = CobsStreamDecoder(maxFrameLength = 4096, sentinel = s)\n```\n\n### `java.io` stream adapters\n\nWrap any `OutputStream` / `InputStream` to write and read self-delimiting frames\n(dependency-free — `java.io` only). `readFrame()` returns `null` at end of stream;\n`frames()` exposes the same reads as a `Sequence`.\n\n```kotlin\nimport dev.firechip.cobs.CobsFramedOutputStream\nimport dev.firechip.cobs.CobsFramedInputStream\n\nCobsFramedOutputStream(socket.outputStream).use { out -\u003e\n    out.writeFrame(byteArrayOf(0x11, 0x00, 0x22)) // encoded frame + 0x00 delimiter\n}\n\nval input = CobsFramedInputStream(socket.inputStream) // reduced / sentinel optional\nfor (packet in input.frames()) handlePacket(packet)\n```\n\n### Coroutines `Flow`\n\n`Flow\u003cByteArray\u003e.cobsFrames()` reassembles a flow of raw chunks (however\nmisaligned) into a flow of decoded packets. `kotlinx-coroutines` is a\n`compileOnly` dependency, so it adds nothing to the published artifact; add it to\nyour own build to use this extension.\n\n```kotlin\nimport dev.firechip.cobs.cobsFrames\n\nserialBytes // Flow\u003cByteArray\u003e of raw reads\n    .cobsFrames() // reduced / skipEmpty / sentinel optional\n    .collect { packet -\u003e handlePacket(packet) }\n```\n\nInvalid encoded input throws `CobsDecodeException`.\n\n## Benchmarks\n\nSingle-threaded JVM throughput on a 1 KiB payload (JDK 25, AMD Ryzen 7 3800XT\nunder WSL2) — ballpark micro-benchmark numbers:\n\n| Operation | Throughput |\n| --------- | ---------- |\n| `Cobs.encode` | ~580 MB/s |\n| `Cobs.decode` | ~850 MB/s |\n| `Cobsr.encode` | ~600 MB/s |\n\nRun with `COBS_BENCH=1 ./gradlew :cobs:testDebugUnitTest --tests '*BenchmarkTest*' --rerun-tasks`.\n\n## Build\n\nRequires JDK 17 or newer (CI builds on JDK 25) and the Android SDK\n(`compileSdk 35`).\n\n```console\n./gradlew :cobs:assembleRelease   # -\u003e cobs/build/outputs/aar/cobs-release.aar\n./gradlew :cobs:testDebugUnitTest # unit tests (golden vectors)\n```\n\nPushing a `v*` tag builds the `.aar` in CI and attaches it to a GitHub release.\n\n## License\n\nMIT (c) 2026 Alexander Salas Bastidas ([Firechip](https://firechip.dev)). See\n[LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffirechip%2Fcobs_codec_kt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffirechip%2Fcobs_codec_kt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffirechip%2Fcobs_codec_kt/lists"}