Decode J1939 metadata for compliant frames and add a struct with J1939
metadata
This commit is contained in:
+43
-1
@@ -2,13 +2,55 @@ import argparse
|
|||||||
import polars as pl
|
import polars as pl
|
||||||
|
|
||||||
def get_j1939_mask() -> pl.Expr:
|
def get_j1939_mask() -> pl.Expr:
|
||||||
|
"""
|
||||||
|
Returns a Polars expression representing the strict J1939 filtering rules.
|
||||||
|
"""
|
||||||
id_int = pl.col("ID").str.to_integer(base=16).cast(pl.UInt32)
|
id_int = pl.col("ID").str.to_integer(base=16).cast(pl.UInt32)
|
||||||
return (
|
return (
|
||||||
(id_int > 0x7FF) &
|
(id_int > 0x7FF) &
|
||||||
((id_int & 0x02000000) == 0) &
|
((id_int % 33554432 // 16777216) == 0) &
|
||||||
(pl.col("DLC") <= 8)
|
(pl.col("DLC") <= 8)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def decode_j1939(lf: pl.LazyFrame) -> pl.LazyFrame:
|
||||||
|
"""
|
||||||
|
Decodes J1939 fields and bundles them into a Struct column.
|
||||||
|
"""
|
||||||
|
id_int = pl.col("ID").str.to_integer(base=16).cast(pl.UInt32)
|
||||||
|
mask = get_j1939_mask()
|
||||||
|
|
||||||
|
priority = (id_int // 67108864) % 8
|
||||||
|
pf = (id_int // 65536) % 256
|
||||||
|
ps = (id_int // 256) % 256
|
||||||
|
sa = id_int % 256
|
||||||
|
|
||||||
|
da = pl.when(pf < 240).then(ps).otherwise(pl.lit(255, dtype=pl.UInt8))
|
||||||
|
pgn = pl.when(pf < 240).then((id_int // 256) % 65536).otherwise((id_int // 256) % 262144).cast(pl.UInt32)
|
||||||
|
|
||||||
|
j1939_struct = pl.struct([
|
||||||
|
priority.cast(pl.UInt8).alias("Priority"),
|
||||||
|
pf.cast(pl.UInt8).alias("PF"),
|
||||||
|
ps.cast(pl.UInt8).alias("PS"),
|
||||||
|
sa.cast(pl.UInt8).alias("SA"),
|
||||||
|
da.cast(pl.UInt8).alias("DA"),
|
||||||
|
pgn.alias("PGN")
|
||||||
|
])
|
||||||
|
|
||||||
|
return lf.with_columns(
|
||||||
|
pl.when(mask).then(j1939_struct).otherwise(None).alias("j1939_metadata")
|
||||||
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description="CAN Log J1939 Decoder")
|
||||||
|
parser.add_argument("input_parquet", help="Path to the parsed .parquet file")
|
||||||
|
parser.add_argument("output_parquet", help="Path to save the decoded .parquet file")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
print(f"[*] Loading {args.input_parquet}")
|
||||||
|
lf = pl.scan_parquet(args.input_parquet)
|
||||||
|
|
||||||
|
print("[*] Decoding J1939 IDs into a nested Struct column")
|
||||||
|
lf_decoded = decode_j1939(lf)
|
||||||
|
|
||||||
|
print(f"[*] Saving decoded data to {args.output_parquet}")
|
||||||
|
lf_decoded.sink_parquet(args.output_parquet)
|
||||||
|
|||||||
Reference in New Issue
Block a user