npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@emdzej/ncsx-coder

v0.8.0

Published

Top-level coding orchestrator: chassis + FA + FSW/PSW edits → per-SG netto buffers ready for CODIERDATEN_SCHREIBEN.

Readme

@emdzej/ncsx-coder

End-to-end coding orchestrator. Takes a chassis bundle, a user FA, and a list of FSW/PSW edits, and produces a CodingPlan[] — one entry per SG that needs coding, each with the encoded netto buffer ready to ship to apiJob(sgbd, 'SG_CODIEREN', hex(netto), '').

This is the single entry point higher-level tools (CLI, web app, automation) reach for when they want to translate "user said: change KEYCARDREADER to eingebaut" into "bytes go on the wire here".

Spec: ../../docs/coding-flow.md.

What it does

FA string ──→ faToAsw ──→ AswSet ──→ selectEcus ──→ in-scope SGs
                                                          │
                                                          ▼
                            per-SG edits ──→ load CABD ──→ encodeField → netto bytes
                                                          │
                                                          ▼
                                                   CodingPlan { sgbd, jobName, netto, … }
  1. faToAsw(fa, { chassis }) — convert the FA string into the ASW bit set.
  2. selectEcus(chassis, asw) — pick in-scope SGs by walking SGAUSWAHL_*.
  3. For each selected SG, group the edits that target it:
    • if edit.sgName is set, only that SG;
    • otherwise, any SG whose CABD has a matching FSW id.
  4. For each (SG, edits) pair, lazily load the CABD .Cxx file, find the PARZUWEISUNG_FSW row for each FSW id, build a CabdRule, encode the PSW value into the SG's netto buffer.
  5. Return one CodingPlan per SG with the final netto byte buffer.

Install

pnpm add @emdzej/ncsx-coder
# or:
"@emdzej/ncsx-coder": "workspace:*"

Quick start

import { loadChassis } from '@emdzej/ncsx-chassis';
import { nodeChassisSource } from '@emdzej/ncsx-chassis/node';
import { planCoding } from '@emdzej/ncsx-coder';

const chassis = await loadChassis(nodeChassisSource('…/DATEN'), 'E46');

const plans = await planCoding({
  chassis,
  fa: '0205 0502 0524',
  edits: [
    // Numeric FSW + PSW for now — name→id resolution is the next planned addition.
    { sgName: 'KMB', fsw: 0x025F, psw: 0x01 }, // KEYCARDREADER = eingebaut
  ],
});

for (const plan of plans) {
  console.log(plan.sgName, plan.sgbd, plan.jobName, plan.netto.length, 'bytes');
  // Hand plan.netto to apiJob(plan.sgbd, plan.jobName, hexEncode(plan.netto), '')
}

API

planCoding(options: PlanCodingOptions): Promise<CodingPlan[]>

interface PlanCodingOptions {
  chassis: Chassis;             // from @emdzej/ncsx-chassis
  fa: string;                   // user-supplied FA string
  edits: CodingEdit[];
  jobName?: string;             // default 'SG_CODIEREN'
  initialNetto?: Map<string, Uint8Array>;  // per-SG starting buffers (from CODIERDATEN_LESEN)
  codingIndex?: Map<string, number>;       // per-SG CI override for CABD .Cxx selection
  onWarning?: (msg: string) => void;
}

interface CodingEdit {
  fsw: number;       // u16 FSW id from PARZUWEISUNG_FSW
  psw: number;       // raw PSW value bytes interpreted as a number (currently)
  sgName?: string;   // pin to one SG; otherwise applies to all SGs that declare this FSW
  index?: number;    // if multiple FSW rows match, pin by INDEX
  blocknr?: number;  // if multiple match, pin by BLOCKNR
}

interface CodingPlan {
  sgName: string;
  sgbd: string;      // EDIABAS SGBD file name (e.g. 'KMBI_E60')
  cabd: string;      // CABD module name (e.g. 'A_KMBI_E60')
  jobName: string;   // e.g. 'SG_CODIEREN'
  netto: Uint8Array; // bytes to flash to this SG
  applied: AppliedEdit[];
  skipped: { edit: CodingEdit; reason: string }[];
  source: SelectionSource;  // which SGAUSWAHL_* block surfaced this SG
}

Initial netto buffer

By default, each SG's plan starts from a zero-filled buffer sized to fit every PARZUWEISUNG_FSW row's WORTADR+BYTEADR. If you want to flash a delta on top of the ECU's current coding, pass initialNetto.get(sgName) for each SG — typically the bytes you just read with CODIERDATEN_LESEN.

What it doesn't do (yet)

  • Read ECU first. Production NCSEXPER calls CODIERDATEN_LESEN for each SG to fetch the current coding, then splices edits on top. The orchestrator currently expects you to pre-fetch and pass via initialNetto.
  • FSW/PSW name resolution. fsw must be the numeric u16 id; psw must be the raw value. chassis.swtFsw / chassis.swtPsw give you the lookups; a thin name-resolver helper is the next planned addition (see STATUS.md resume entry points).
  • Wire transfer. The plan is data; sending it to the ECU is the caller's job — typically @emdzej/ediabasx calling apiJob(plan.sgbd, plan.jobName, hex(plan.netto), '').

Related