laddercodec 0.1.8__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- laddercodec-0.2.0/CHANGELOG.md +134 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/CLAUDE.md +6 -3
- {laddercodec-0.1.8 → laddercodec-0.2.0}/PKG-INFO +1 -1
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/compare_csv.py +13 -2
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/dump_scr_tags.py +7 -13
- {laddercodec-0.1.8 → laddercodec-0.2.0}/docs/guides/csv-format.md +7 -4
- {laddercodec-0.1.8 → laddercodec-0.2.0}/docs/internals/binary-format.md +40 -10
- {laddercodec-0.1.8 → laddercodec-0.2.0}/docs/internals/wire-rendering.md +1 -1
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/cell.py +24 -27
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/csv/contract.py +12 -1
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/csv/parser.py +5 -3
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/csv/writer.py +51 -10
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/decode.py +23 -0
- laddercodec-0.2.0/src/laddercodec/decode_program.py +911 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/drum.py +35 -7
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/math.py +15 -6
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/csv/test_contract.py +31 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/csv/test_converter.py +22 -1
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/csv/test_parser.py +36 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/csv/test_writer.py +98 -0
- laddercodec-0.2.0/tests/fixtures/ladder_captures/drum_weird_branch.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/scr_captures/time_drums.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/scr_captures/time_drums.csv +42 -0
- laddercodec-0.2.0/tests/fixtures/scr_captures/time_drums.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/main.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/main.clipboard.csv +217 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/main.csv +217 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/main.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AckAlarm.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AckAlarm.clipboard.csv +5 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AckAlarm.csv +5 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AckAlarm.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AckAndClearAllAlarms.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AckAndClearAllAlarms.clipboard.csv +8 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AckAndClearAllAlarms.csv +8 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AckAndClearAllAlarms.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AckWarning.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AckWarning.clipboard.csv +5 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AckWarning.csv +5 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AckWarning.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AlmHistorian.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AlmHistorian.clipboard.csv +50 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AlmHistorian.csv +50 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/AlmHistorian.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Blower.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Blower.clipboard.csv +86 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Blower.csv +86 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Blower.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/DisableOutputs.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/DisableOutputs.clipboard.csv +6 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/DisableOutputs.csv +6 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/DisableOutputs.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Heat.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Heat.clipboard.csv +100 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Heat.csv +100 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Heat.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Init.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Init.clipboard.csv +19 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Init.csv +19 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Init.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Maint.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Maint.clipboard.csv +14 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Maint.csv +14 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Maint.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Manual.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Manual.clipboard.csv +11 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Manual.csv +11 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Manual.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ModeChange.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ModeChange.clipboard.csv +17 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ModeChange.csv +17 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ModeChange.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/PLCDateTime.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/PLCDateTime.clipboard.csv +26 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/PLCDateTime.csv +26 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/PLCDateTime.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/PLCErrors.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/PLCErrors.clipboard.csv +15 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/PLCErrors.csv +15 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/PLCErrors.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionBoilerplate.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionBoilerplate.clipboard.csv +11 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionBoilerplate.csv +11 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionBoilerplate.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionErrors.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionErrors.clipboard.csv +45 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionErrors.csv +45 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionErrors.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionExecuteSteps.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionExecuteSteps.clipboard.csv +48 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionExecuteSteps.csv +48 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionExecuteSteps.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionHMI.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionHMI.clipboard.csv +15 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionHMI.csv +15 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionHMI.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionStates.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionStates.clipboard.csv +39 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionStates.csv +39 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ProductionStates.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ReadInputs.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ReadInputs.clipboard.csv +8 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ReadInputs.csv +8 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ReadInputs.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/RecipeChange.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/RecipeChange.clipboard.csv +14 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/RecipeChange.csv +14 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/RecipeChange.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Rotate.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Rotate.clipboard.csv +95 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Rotate.csv +95 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Rotate.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/SFCExample.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/SFCExample.clipboard.csv +144 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/SFCExample.csv +144 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/SFCExample.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/SetOutputs.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/SetOutputs.clipboard.csv +8 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/SetOutputs.csv +8 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/SetOutputs.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/SetOutputsManual.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/SetOutputsManual.clipboard.csv +6 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/SetOutputsManual.csv +6 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/SetOutputsManual.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ThermErrors.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ThermErrors.clipboard.csv +7 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ThermErrors.csv +7 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/ThermErrors.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Validation.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Validation.clipboard.csv +11 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Validation.csv +11 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/Validation.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/WarnTimestamp.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/WarnTimestamp.clipboard.csv +28 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/WarnTimestamp.csv +28 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/WarnTimestamp.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_CopyOrJumpState.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_CopyOrJumpState.clipboard.csv +34 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_CopyOrJumpState.csv +34 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_CopyOrJumpState.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_CtrlCmd2StateRequest.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_CtrlCmd2StateRequest.clipboard.csv +72 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_CtrlCmd2StateRequest.csv +72 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_CtrlCmd2StateRequest.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_IsCmdValid.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_IsCmdValid.clipboard.csv +29 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_IsCmdValid.csv +29 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_IsCmdValid.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_MapCmd2Val.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_MapCmd2Val.clipboard.csv +35 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_MapCmd2Val.csv +35 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_MapCmd2Val.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_MapVal2State.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_MapVal2State.clipboard.csv +19 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_MapVal2State.csv +19 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_MapVal2State.scr +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_StateComplete2Request.clipboard.bin +0 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_StateComplete2Request.clipboard.csv +14 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_StateComplete2Request.csv +14 -0
- laddercodec-0.2.0/tests/fixtures/tumbler/subroutines/sm_StateComplete2Request.scr +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_decode.py +73 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_decode_program.py +196 -296
- laddercodec-0.2.0/tests/ladder/test_decode_program_tumbler.py +33 -0
- laddercodec-0.1.8/CHANGELOG.md +0 -96
- laddercodec-0.1.8/src/laddercodec/decode_program.py +0 -1154
- {laddercodec-0.1.8 → laddercodec-0.2.0}/.claude/settings.local.json +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/.github/workflows/ci.yml +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/.github/workflows/docs.yml +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/.github/workflows/publish.yml +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/.gitignore +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/LICENSE +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/Makefile +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/README.md +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/add-features-workflow.md +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/analyze_scr.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/combine_coverage.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/compare_blobs.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/coverage_golden.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/create_mr_max_csv.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/diag_blob.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/gen_modbus_coverage.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/golden.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/inspect_bin.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/inspect_scr.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/lint.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/pdf_to_png.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/test_decode_scr.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/validate_scr.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/devtools/walk_scr.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/docs/CLAUDE.md +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/docs/gen_reference.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/docs/guides/adding-instructions.md +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/docs/guides/decoding.md +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/docs/guides/encoding.md +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/docs/guides/troubleshooting.md +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/docs/index.md +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/docs/internals/instruction-blobs.md +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/mkdocs.yml +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/pyproject.toml +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/__init__.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/_grid.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/binary_helpers.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/csv/__init__.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/csv/ast.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/csv/bundle.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/csv/converter.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/csv/token_parser.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/empty_multirow.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/encode.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/encode_multi.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/__init__.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/call.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/coil.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/comparison.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/contact.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/copy.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/counter.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/email.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/end.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/family.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/forloop.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/home.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/position.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/raw.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/return_.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/search.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/send_receive.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/shift.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/timer.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/instructions/velocity.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/model.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/resources/empty_multirow_rule_minimal.scaffold.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/src/laddercodec/topology.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/__init__.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/csv/test_bundle.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/csv/test_token_parser.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/csv/test_writer_raw_validator.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/coverage.ckp +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/blockcopy__block.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/blockcopy__block.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/blockcopy__oneshot.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/blockcopy__oneshot.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/blockcopy__to_ascii.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/blockcopy__to_ascii.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/blockcopy__to_value.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/blockcopy__to_value.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/call__basic.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/call__basic.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__and.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__and.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__eq.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__eq.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__fall.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__fall.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__ge.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__ge.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__gt.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__gt.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__immediate.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__immediate.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__le.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__le.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__lt.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__lt.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__nc.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__nc.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__ne.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__ne.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__no.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__no.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__or.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__or.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__rise.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/cond__rise.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__literal_float.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__literal_float.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__literal_int.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__literal_int.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__oneshot.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__oneshot.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__tag.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__tag.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_ascii.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_ascii.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_binary.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_binary.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_text.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_text.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_text_exp.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_text_exp.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_text_sz.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_text_sz.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_text_term.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_text_term.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_value.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/copy__to_value.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/count_down.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/count_down.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/count_up__down.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/count_up__down.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/count_up__reset.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/count_up__reset.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/end.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/end.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/event_drum__basic.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/event_drum__basic.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/event_drum__full.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/event_drum__full.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/event_drum__jog.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/event_drum__jog.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/event_drum__jump.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/event_drum__jump.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/event_drum__max.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/event_drum__max.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/fill__literal.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/fill__literal.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/fill__oneshot.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/fill__oneshot.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/fill__tag.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/fill__tag.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/forloop__basic.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/forloop__basic.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/forloop__oneshot.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/forloop__oneshot.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/latch__block.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/latch__block.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/latch__immediate.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/latch__immediate.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/latch__tag.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/latch__tag.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/math__decimal.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/math__decimal.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/math__hex.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/math__hex.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/math__oneshot.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/math__oneshot.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/off_delay__tof.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/off_delay__tof.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/on_delay__rton.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/on_delay__rton.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/on_delay__ton.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/on_delay__ton.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/out__block.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/out__block.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/out__immediate.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/out__immediate.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/out__oneshot.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/out__oneshot.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/out__tag.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/out__tag.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_bits.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_bits.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_bits__oneshot.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_bits__oneshot.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_text.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_text.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_text__allow_whitespace.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_text__allow_whitespace.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_text__oneshot.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_text__oneshot.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_words.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_words.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_words__oneshot.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/pack_words__oneshot.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/raw_instructions__email.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/raw_instructions__email.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/raw_instructions__home.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/raw_instructions__home.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/raw_instructions__position.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/raw_instructions__position.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/raw_instructions__velocity.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/raw_instructions__velocity.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__rtu_click_block.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__rtu_click_block.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__rtu_click_single.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__rtu_click_single.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__rtu_modbus_block.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__rtu_modbus_block.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__rtu_modbus_single.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__rtu_modbus_single.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__tcp_click_coil.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__tcp_click_coil.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__tcp_click_input.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__tcp_click_input.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__tcp_click_input_reg.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__tcp_click_input_reg.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__tcp_click_wordswap.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/receive__tcp_click_wordswap.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/reset__block.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/reset__block.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/reset__immediate.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/reset__immediate.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/reset__tag.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/reset__tag.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/return_early__basic.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/return_early__basic.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__continuous.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__continuous.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__eq.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__eq.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__ge.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__ge.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__gt.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__gt.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__le.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__le.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__lt.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__lt.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__ne.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__ne.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__oneshot.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/search__oneshot.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__error_off.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__error_off.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__errorcode_off.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__errorcode_off.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__rtu_click_block.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__rtu_click_block.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__rtu_click_single.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__rtu_click_single.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__rtu_modbus_block.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__rtu_modbus_block.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__rtu_modbus_single.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__rtu_modbus_single.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__sending_off.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__sending_off.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__success_off.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__success_off.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__tcp_click_coil.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__tcp_click_coil.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__tcp_click_coils.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__tcp_click_coils.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__tcp_click_wordswap.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/send__tcp_click_wordswap.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/shift__basic.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/shift__basic.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/time_drum__basic.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/time_drum__basic.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/time_drum__basic_td.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/time_drum__basic_td.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/unpack_to_bits.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/unpack_to_bits.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/unpack_to_bits__oneshot.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/unpack_to_bits__oneshot.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/unpack_to_words.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/unpack_to_words.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/unpack_to_words__oneshot.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/unpack_to_words__oneshot.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/golden/verify_progress.log +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/coverage/subroutines/coverage_sub.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-1row-fullwire-nop.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-1row-fullwire-nop.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-1row-max1400.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-1row-max1400.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-1row-styled-mixed.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-1row-styled-mixed.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-2row-max1324.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-2row-max1324.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-2row-nop-wire.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-2row-nop-wire.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-32row-sparse.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-32row-sparse.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-3row-mixed.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/cmt-3row-mixed.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-2row-cond__and.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-2row-cond__and.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-2row-r0only.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-2row-r0only.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-2row-spread.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-2row-spread.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-3row-branch.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-3row-branch.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-3row-or-colA.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-3row-or-colA.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-3row-or.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-3row-or.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-3row-scatter.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-3row-scatter.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-6row-multi-output.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-6row-multi-output.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-coil-timer-ret.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-coil-timer-ret.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-compare-ge.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-compare-ge.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-compare-series.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-compare-series.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-compare-timer.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-compare-timer.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-cond__and.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-cond__and.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-copy-multirow-2af-T.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-copy-multirow-2af-T.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-copy-multirow-2af.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-copy-multirow-2af.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-count_down-row0-data.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-count_down-row0-data.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-no-out.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-no-out.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-series.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-series.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-timer-off.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-timer-off.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-timer-on.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-timer-on.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-timer-ret.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/instr-timer-ret.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-2rung-2row.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-2rung-2row.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-2rung-wire.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-2rung-wire.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-3rung-wire-nop.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-3rung-wire-nop.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-2rung-2row.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-2rung-2row.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-2rung-both.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-2rung-both.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-2rung-r1-max1400.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-2rung-r1-max1400.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-all.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-all.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-multirow-multiinstructions.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-multirow-multiinstructions.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-multirow-nopaddedrows.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-multirow-nopaddedrows.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-multirow.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-multirow.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-instr-2rung.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-instr-2rung.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-instr-cond__and.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/mr-instr-cond__and.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/nc-1row-empty.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/nc-1row-empty.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/nc-1row-fullwire-nop.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/nc-1row-fullwire-nop.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/nc-32row-empty.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/nc-32row-empty.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/nc-3row-t-junction.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/nc-3row-t-junction.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/nc-4row-vertical.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/nc-4row-vertical.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/ladder_captures/golden/verify_progress.log +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/scr_captures/counter_scr.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/scr_captures/counter_scr.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/scr_captures/counter_scr.scr +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/scr_captures/coverage.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/scr_captures/coverage.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/scr_captures/coverage.scr +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/scr_captures/or_topology.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/scr_captures/or_topology.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/scr_captures/or_topology.scr +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/scr_captures/shift_scr.bin +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/scr_captures/shift_scr.csv +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/fixtures/scr_captures/shift_scr.scr +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/golden_io.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_counter.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_decode_multi.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_decode_rtf_oracle.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_empty_multirow.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_encode.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_encode_multi.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_forloop.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_math.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_model.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_shift.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/ladder/test_verify_status.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/test_coverage.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/test_public_api.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/tests/test_smoke.py +0 -0
- {laddercodec-0.1.8 → laddercodec-0.2.0}/uv.lock +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
<!-- Style guide: one sentence per entry. Describe the user-visible effect, not the
|
|
4
|
+
implementation. Group related fixes/features into a single entry when they share
|
|
5
|
+
a theme. Breaking changes and migration steps can be longer — users need the
|
|
6
|
+
specifics. Detail belongs in commit messages and PR descriptions, not here.
|
|
7
|
+
|
|
8
|
+
Review and condense before release — entries accumulate during development and
|
|
9
|
+
should be edited into shape before moving from Unreleased to a version heading. -->
|
|
10
|
+
|
|
11
|
+
## 0.2.0
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **SCR decode**: correct the row-topology block framing — every row (including row 0) uses one uniform block format, fixing branch rungs whose wires (`T`/`|`/`-`) were silently dropped whenever a continuation row's first right-wired cell carried segment flag 1.
|
|
15
|
+
- **SCR decode**: accept placement-ordered flag-table entries — native captures store columns out of order (e.g. `[6,1,0,3,2,4,5]`), which the old sorted-order validation rejected.
|
|
16
|
+
- **SCR decode**: drop orphaned editor-debris wire rows stored above a rung's true row 0 (observed under drum boxes), matching what Click's own clipboard copy produces.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- **SCR decode**: replace the heuristic topology parser (leading-row guessing, count_down special cases, end-marker scanning) with a deterministic parser derived from the verified format — see `docs/internals/binary-format.md` §"SCR row-topology blocks" for the spec.
|
|
20
|
+
- **SCR decode**: `decode_program()` now parses rung records with a single forward cursor — comments, topology, and instructions are read from explicit lengths and counts instead of scanning for signatures, so comments attach to their own rung by construction and malformed files fail loudly with the byte offset (see §"SCR rung records" in the binary format doc).
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- **Tumbler fixture**: 34 real Click programs (`tests/fixtures/tumbler/`), each pairing the internal `.scr` program file with a clipboard capture of the same program; `decode_program()` output is regression-tested byte-identical against the clipboard CSVs.
|
|
24
|
+
- **Devtools**: `compare_csv.py` normalizes `R` vs `R1`/`R2` rung markers before comparing, so scr-derived and clipboard-saved CSVs diff cleanly.
|
|
25
|
+
|
|
26
|
+
## 0.1.9
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
- **Time drums**: encode and decode all five time bases (`Tms`/`Ts`/`Tm`/`Th`/`Td`), plus jog and jump, matching event drums.
|
|
30
|
+
- **CSV writer**: `write_csv(path, rungs, index=True)` emits 1-based sequential rung markers (`R1`, `R2`, `R3`, …) instead of plain `R`; readers accept `R` optionally followed by digits, so indexed files still round-trip.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- **Drum decode**: single-step event and time drums now decode from `Scr*.tmp` files instead of falling back to `RawInstruction`.
|
|
34
|
+
- **Drum decode**: a stray NOP stranded on a drum's pin row is dropped instead of surfacing as a spurious `NOP` that broke `write_csv`.
|
|
35
|
+
- **CSV writer**: a tall instruction (drum, timer, counter, …) with a wire branch or content running below its body keeps its rows positional instead of collapsing the following rows up, fixing `WriterError`/lost geometry on those rungs.
|
|
36
|
+
|
|
37
|
+
### Performance
|
|
38
|
+
- `decode_program()` is ~48% faster — topology block scanning uses `bytes.find()` instead of byte-by-byte iteration, and hot loops cache `len(data)` and precomputed constants.
|
|
39
|
+
- `encode()` is ~35% faster — cell headers use a single pre-compiled `struct.Struct.pack` instead of 8 separate calls, and Math blobs use pre-computed empty slot bytes instead of 1000 per-instruction loop iterations.
|
|
40
|
+
|
|
41
|
+
## 0.1.8
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
- **CSV writer**: downgrade trailing blank row mismatch from error to warning
|
|
45
|
+
when a tall instruction's stripped continuation absorbs extra blank rows on
|
|
46
|
+
read-back — fixes `WriterError` on rungs with blank rows beyond an
|
|
47
|
+
instruction's visual height
|
|
48
|
+
|
|
49
|
+
## 0.1.7
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
- **SCR decode**: skip pure vertical pass-through rows in implied modifier
|
|
53
|
+
row fallback, preventing `|` → `T` and blank → `-` corruption on
|
|
54
|
+
continuation rows
|
|
55
|
+
- **CSV converter**: recognize `Contact`/`CompareContact` objects with
|
|
56
|
+
`wire_down=True` during wire hydration, not just bare string tokens
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
- **SCR decode**: remove `_implied_modifier_row_offsets` fallback — SCR
|
|
60
|
+
continuation row topology already encodes per-row horizontal connectivity
|
|
61
|
+
explicitly, verified across 883 rungs in 47 SCR files
|
|
62
|
+
|
|
63
|
+
## 0.1.6
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
- **SCR decode**: replace backward/brute-force topology block scanning with a
|
|
67
|
+
single forward pass, fixing false positive matches from flag-table tail bytes
|
|
68
|
+
that caused spurious empty rungs with inflated row counts
|
|
69
|
+
|
|
70
|
+
## 0.1.5
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
- **Encode**: remove AF summary block — Click accepts multi-AF rungs without
|
|
74
|
+
it, eliminating complex gating logic
|
|
75
|
+
- **CSV**: consolidate tall-instruction padding into shared hydrate/dehydrate
|
|
76
|
+
helpers in converter and writer
|
|
77
|
+
|
|
78
|
+
### Added
|
|
79
|
+
- **Devtools**: `combine_coverage.py` — combine random coverage fixtures into
|
|
80
|
+
a single multi-row rung for paste smoke-testing
|
|
81
|
+
- **Devtools**: `coverage_golden.py` now regenerates all bins unconditionally
|
|
82
|
+
|
|
83
|
+
## 0.1.4
|
|
84
|
+
|
|
85
|
+
### Fixed
|
|
86
|
+
- **CSV**: preserve multi-row AF round-trips, including pinned/tall AF blocks
|
|
87
|
+
away from row 0, multiple tall blocks in one rung, and generic tall
|
|
88
|
+
continuation rows
|
|
89
|
+
- **SCR decode**: restore omitted wiring for generic tall AF continuation rows
|
|
90
|
+
- **CSV writer**: fail loudly when emitted CSV rows lose decoded rung
|
|
91
|
+
semantics by reparsing writer output and checking for row, condition, or AF
|
|
92
|
+
mismatches before writing to disk
|
|
93
|
+
|
|
94
|
+
## 0.1.3
|
|
95
|
+
|
|
96
|
+
### Fixed
|
|
97
|
+
- **RTF decode**: parse RTF comments structurally instead of regex-based
|
|
98
|
+
stripping, handling nested groups, font/color tables, and style toggles
|
|
99
|
+
correctly
|
|
100
|
+
- **RTF decode**: handle `\uN` unicode escape sequences (signed 16-bit) and
|
|
101
|
+
validate `ansicpg1252` before decoding
|
|
102
|
+
- **CSV**: preserve quoted string literals in AF token positional args — e.g.
|
|
103
|
+
`copy("d",TXT1)` no longer loses its quotes during parse
|
|
104
|
+
- **Search instruction**: store text-search operands with quotes end-to-end,
|
|
105
|
+
removing the strip-on-decode/re-add-on-encode anti-pattern
|
|
106
|
+
|
|
107
|
+
### Added
|
|
108
|
+
- **Encode**: auto-sanitize non-ASCII characters (curly quotes, em-dashes,
|
|
109
|
+
arrows, etc.) in rung comments before RTF conversion via NFKD normalization
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
## 0.1.2
|
|
113
|
+
|
|
114
|
+
### Fixed
|
|
115
|
+
- **Math**: preserve duplicate operands and normalize parenthesis spacing
|
|
116
|
+
|
|
117
|
+
## 0.1.1
|
|
118
|
+
|
|
119
|
+
### Fixed
|
|
120
|
+
- **Encode**: correct `row_span` for tall AF instructions and single-rung list
|
|
121
|
+
routing
|
|
122
|
+
|
|
123
|
+
## 0.1.0
|
|
124
|
+
|
|
125
|
+
Initial release. Originally prototyped in
|
|
126
|
+
[clicknick](https://github.com/ssweber/clicknick), then developed into a
|
|
127
|
+
standalone library here.
|
|
128
|
+
|
|
129
|
+
- Encode `Rung` objects or CSV into Click clipboard binary
|
|
130
|
+
- Decode clipboard binary back into structured Python objects
|
|
131
|
+
- Decode `Scr*.tmp` program files into `Program` objects
|
|
132
|
+
- All standard Click instruction types supported natively
|
|
133
|
+
- `RawInstruction` passthrough for unknown blob types
|
|
134
|
+
- Zero runtime dependencies
|
|
@@ -98,6 +98,7 @@ tests/
|
|
|
98
98
|
│ ├── test_decode.py # decode() tests
|
|
99
99
|
│ ├── test_decode_multi.py # decode() multi-rung tests
|
|
100
100
|
│ ├── test_decode_program.py # decode_program() program file tests
|
|
101
|
+
│ ├── test_decode_program_tumbler.py # 34 real programs: scr decode == clipboard CSV
|
|
101
102
|
│ ├── test_verify_status.py # Golden verification status check
|
|
102
103
|
│ ├── test_model.py # InstructionType, operand validation
|
|
103
104
|
│ └── test_empty_multirow.py # Payload synthesis for rows 1..32
|
|
@@ -109,10 +110,12 @@ tests/
|
|
|
109
110
|
│ ├── test_token_parser.py # Condition + AF token parsing
|
|
110
111
|
│ └── test_writer.py # CSV writer tests
|
|
111
112
|
└── fixtures/
|
|
112
|
-
|
|
113
|
+
├── ladder_captures/golden/ # Golden CSV/BIN fixtures
|
|
114
|
+
├── scr_captures/ # Scr program files + clipboard bins (decode_program)
|
|
115
|
+
└── tumbler/ # 34 real programs: <name>.scr + <name>.clipboard.{bin,csv}
|
|
113
116
|
```
|
|
114
117
|
|
|
115
|
-
Golden fixtures verified through Click paste round-trip.
|
|
118
|
+
Golden fixtures verified through Click paste round-trip. The tumbler fixture pairs each Click internal program file (`.scr`) with a clipboard capture of the same program; `devtools/compare_csv.py <dir>` compares `<name>.csv` (scr decode) against `<name>.clipboard.csv` ground truth.
|
|
116
119
|
|
|
117
120
|
## Binary Format
|
|
118
121
|
|
|
@@ -157,7 +160,7 @@ All tested shapes pass Click round-trip (verified via paste → copy-back):
|
|
|
157
160
|
|
|
158
161
|
The clipboard decoder (`decode.py`) reads Click clipboard binaries back into structured data. Validated against a 37-rung native capture covering all basic instruction types.
|
|
159
162
|
|
|
160
|
-
The program file decoder (`decode_program.py`) reads Click's internal `Scr*.tmp` files. Returns a `Program` with name, index, and all rungs. Validated against 114-rung coverage fixture
|
|
163
|
+
The program file decoder (`decode_program.py`) reads Click's internal `Scr*.tmp` files. Returns a `Program` with name, index, and all rungs. Validated against the 114-rung coverage fixture, shift/counter/drum programs, and the 34-program tumbler fixture (byte-identical CSV vs clipboard captures). Row topology uses the uniform row-block framing documented in `docs/internals/binary-format.md` §"SCR row-topology blocks".
|
|
161
164
|
|
|
162
165
|
**All standard Click instruction types decoded natively:**
|
|
163
166
|
- Contacts: NO, NC, edge (rise/fall), immediate (NO/NC)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: laddercodec
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Binary codec for AutomationDirect CLICK PLC ladder clipboard format
|
|
5
5
|
Project-URL: Repository, https://github.com/ssweber/laddercodec
|
|
6
6
|
Project-URL: Documentation, https://ssweber.github.io/laddercodec/
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"""Compare {slug}.csv against {slug}.clipboard.csv in a directory.
|
|
2
2
|
|
|
3
|
-
Reports which pairs are identical and which differ.
|
|
3
|
+
Reports which pairs are identical and which differ. Rung markers are
|
|
4
|
+
normalized before comparison (indexed ``R1``/``R2`` vs plain ``R``), since
|
|
5
|
+
scr-derived bundles are written with ``index=True`` while clipboard saves
|
|
6
|
+
are not.
|
|
4
7
|
|
|
5
8
|
Usage:
|
|
6
9
|
uv run devtools/compare_csv.py <directory>
|
|
@@ -8,9 +11,17 @@ Usage:
|
|
|
8
11
|
|
|
9
12
|
from __future__ import annotations
|
|
10
13
|
|
|
14
|
+
import re
|
|
11
15
|
import sys
|
|
12
16
|
from pathlib import Path
|
|
13
17
|
|
|
18
|
+
_INDEXED_MARKER = re.compile(r"^R\d+(?=,)")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _normalized_lines(path: Path) -> list[str]:
|
|
22
|
+
text = path.read_text(encoding="utf-8")
|
|
23
|
+
return [_INDEXED_MARKER.sub("R", line) for line in text.splitlines()]
|
|
24
|
+
|
|
14
25
|
|
|
15
26
|
def main() -> None:
|
|
16
27
|
if len(sys.argv) != 2:
|
|
@@ -42,7 +53,7 @@ def main() -> None:
|
|
|
42
53
|
missing += 1
|
|
43
54
|
continue
|
|
44
55
|
|
|
45
|
-
if base_path
|
|
56
|
+
if _normalized_lines(base_path) == _normalized_lines(clip_path):
|
|
46
57
|
print(f" IDENTICAL {slug}")
|
|
47
58
|
identical += 1
|
|
48
59
|
else:
|
|
@@ -25,20 +25,14 @@ def main() -> None:
|
|
|
25
25
|
print(f"\nRung {si}:")
|
|
26
26
|
cursor = sec_off + 6
|
|
27
27
|
for ii in range(count):
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if blob8:
|
|
31
|
-
row = data[cursor]
|
|
32
|
-
col = data[cursor + 1]
|
|
33
|
-
blob_start = cursor + 8
|
|
34
|
-
cls, typ, end_off, next_pos, m1 = blob8
|
|
35
|
-
elif blob9:
|
|
36
|
-
row = data[cursor + 1]
|
|
37
|
-
col = data[cursor + 2]
|
|
38
|
-
blob_start = cursor + 9
|
|
39
|
-
cls, typ, end_off, next_pos, m1 = blob9
|
|
40
|
-
else:
|
|
28
|
+
blob = _parse_blob(data, cursor + 8)
|
|
29
|
+
if not blob:
|
|
41
30
|
break
|
|
31
|
+
row = data[cursor]
|
|
32
|
+
col = data[cursor + 1]
|
|
33
|
+
blob_start = cursor + 8
|
|
34
|
+
cls, typ, end_off, m1 = blob
|
|
35
|
+
next_pos = end_off + 2 + data[end_off] # trailer-aware advance
|
|
42
36
|
|
|
43
37
|
# Parse tagged fields
|
|
44
38
|
pos = blob_start
|
|
@@ -6,7 +6,7 @@ used by `laddercodec` CSV tooling and by `pyrung.click.to_ladder()`.
|
|
|
6
6
|
Relevant entry points:
|
|
7
7
|
|
|
8
8
|
- `laddercodec.read_csv(path)`
|
|
9
|
-
- `laddercodec.write_csv(path, rungs)`
|
|
9
|
+
- `laddercodec.write_csv(path, rungs, *, index=False)`
|
|
10
10
|
- `laddercodec.csv.bundle.parse_bundle(directory)`
|
|
11
11
|
- `pyrung.click.to_ladder(program, tag_map)`
|
|
12
12
|
- `pyrung.click.LadderBundle.write(directory)`
|
|
@@ -58,6 +58,9 @@ marker,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF
|
|
|
58
58
|
|
|
59
59
|
- `marker`:
|
|
60
60
|
- `R` => first row of a rung
|
|
61
|
+
- `R<n>` (e.g. `R1`, `R2`) => first row of a rung, with an optional 1-based
|
|
62
|
+
index. `write_csv(path, rungs, index=True)` emits these; the index is
|
|
63
|
+
decorative and ignored on read.
|
|
61
64
|
- `""` (blank) => continuation row of current rung
|
|
62
65
|
- `#` => comment row
|
|
63
66
|
- `AF`:
|
|
@@ -66,8 +69,8 @@ marker,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF
|
|
|
66
69
|
|
|
67
70
|
Rung segmentation rule for consumers:
|
|
68
71
|
|
|
69
|
-
- A rung starts at each row
|
|
70
|
-
`R` or EOF.
|
|
72
|
+
- A rung starts at each row whose `marker` is `R` optionally followed by digits
|
|
73
|
+
(`R`, `R1`, `R2`, ...) and continues until the next such marker or EOF.
|
|
71
74
|
|
|
72
75
|
## Comment rows
|
|
73
76
|
|
|
@@ -464,4 +467,4 @@ On any issue:
|
|
|
464
467
|
3. Treat `AF` as an opaque canonical token string unless your decoder
|
|
465
468
|
intentionally parses token grammar.
|
|
466
469
|
4. Treat unknown future token names as extension points (fail closed if strict).
|
|
467
|
-
5. Segment rungs by `marker
|
|
470
|
+
5. Segment rungs by a `marker` of `R` optionally followed by digits (`R`, `R1`, `R2`, ...).
|
|
@@ -198,24 +198,54 @@ The instruction blob content (tag IDs, operand values, wire types) is **identica
|
|
|
198
198
|
|
|
199
199
|
The embedded fields at offsets +0 through +6 after the type code correspond to clipboard cell header offsets +0x09 through +0x10. The `end_offset` is an absolute file pointer to the blob boundary — the same boundary that clipboard's `find_blob_boundary()` derives by scanning tags. Tags use length-prefixed strings (no `FFFFFFFF` sentinel).
|
|
200
200
|
|
|
201
|
+
The byte at `end_offset` is a 1-byte trailer length (observed 0 or 1): the next structure starts at `end_offset + 2 + data[end_offset]`. Certain instruction encodings (`RD`/`SD` always; `Copy`/`Math`/`Out`/`Drum` sometimes) emit a 1-byte trailer whose value is opaque.
|
|
202
|
+
|
|
203
|
+
## SCR rung records
|
|
204
|
+
|
|
205
|
+
An SCR file is a header followed by one rung record per rung, in order, parseable with a single forward cursor:
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
RUNG = [2B rung_index] -- 1-based ordinal; asserted sequential
|
|
209
|
+
[4B rtf_len][rtf body] -- comment; rtf_len = 0 means none
|
|
210
|
+
TOPOLOGY -- row-topology block (below)
|
|
211
|
+
[2B instr_count] -- 0 = empty rung (nothing follows)
|
|
212
|
+
[4B section_marker] -- only when instr_count > 0
|
|
213
|
+
instr_count x ENTRY -- 8-byte header + blob (see framing above)
|
|
214
|
+
ENTRY = [1B row_1based][1B col][1B b2][1B b3][1B entry_seq][3B 00] + blob
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Rung 0 carries a 7-byte file prelude instead of `rung_index`: `[2B file_marker][0d][4B total_rung_records]`. `file_marker` equals the per-file `section_marker` constant (opaque; validation magic only), and `total_rung_records` counts every rung record in the file.
|
|
218
|
+
|
|
219
|
+
Programs end with 1–4 ordinary content-less rungs (the empty editor rungs below the last programmed rung; some carry a fully-wired row) — the decoder drops trailing records with no instructions and no comment. Files with `prog_idx == 1` (the main program) carry a 2-byte tail after the last record; subroutines end exactly at the last record.
|
|
220
|
+
|
|
201
221
|
## SCR row-topology blocks
|
|
202
222
|
|
|
203
223
|
SCR files store per-rung wire topology in structured blocks that precede each rung's instruction section. Each block encodes the right-wire and segment-flag data that clipboard stores per-cell in the grid.
|
|
204
224
|
|
|
205
225
|
```
|
|
206
|
-
[2B row_word][03 00 00]
|
|
207
|
-
|
|
208
|
-
[
|
|
209
|
-
[
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
226
|
+
[2B row_word][03 00 00] -- 5-byte header; row_word = stored rows + 1
|
|
227
|
+
{ row block } x (row_word - 1) -- one per grid row, in row order (row 0 first)
|
|
228
|
+
[20 00] -- end marker
|
|
229
|
+
[wire-down table] -- exactly 32 column entries (see below)
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Every row block — including row 0's — has the same uniform format:
|
|
233
|
+
|
|
213
234
|
```
|
|
235
|
+
[1B flag][1B count][00] + count x ([1B seg][1B col])
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
- `flag` — the +0x19 segment flag of the row's AF (col 31) cell. 1 for normal output/coil/NOP rows, 0 for tall segment-0 instructions (timer/counter/drum).
|
|
239
|
+
- `count` — number of right-wired cells on the row (condition cells plus AF when present). `count = 0` is an empty row: the 3-byte block `[flag][00][00]`.
|
|
240
|
+
- Each entry pairs a cell's +0x19 segment flag with its column index (0–31, 31 = AF). Entries are **placement-ordered** — the column sequence is usually ascending but not guaranteed (native captures include orders like `[6,1,0,3,2,4,5]`), so columns must be treated as a set.
|
|
241
|
+
|
|
242
|
+
A row block whose entries include col 0 with every condition-cell seg = 1 carries the grid-row-0 signature (row 0 is exempt from the per-row segment boundary). SCR can retain orphaned wire rows *above* the true row 0 — editor debris under a tall instruction box — which Click's own clipboard copy omits; the decoder drops non-empty stored rows preceding the first row with the row-0 signature.
|
|
214
243
|
|
|
215
|
-
|
|
244
|
+
The wire-down table after the `20 00` marker has exactly one entry per column 0–31:
|
|
216
245
|
|
|
217
246
|
```
|
|
218
|
-
|
|
247
|
+
no down wires: [00 00]
|
|
248
|
+
down wires: [1B count][00][count x 1-based row index]
|
|
219
249
|
```
|
|
220
250
|
|
|
221
|
-
|
|
251
|
+
This table is the SCR serialization of the per-cell down flag (+0x21) that clipboard stores on each cell — it lists every down wire, including those carried by contact cells (rendered as a `T:` prefix, see [wire rendering](wire-rendering.md)). It is therefore a superset of the visible `T`/`|` wire tokens.
|
|
@@ -21,7 +21,7 @@ Wire tokens are classified by (right, down) only — the segment flag is indepen
|
|
|
21
21
|
| 1 | 1 | `T` | Branch junction (right + down) |
|
|
22
22
|
| 0 | 0 | *(blank)* | No wire |
|
|
23
23
|
|
|
24
|
-
Instruction cells (contacts, coils) also set right=1 — they behave like horizontal wires with instruction data layered on top.
|
|
24
|
+
Instruction cells (contacts, coils) also set right=1 — they behave like horizontal wires with instruction data layered on top. A contact cell can additionally set down=1 (a branch rooted directly under the contact): since right is already 1, that's the T shape, and the CSV renders it as a `T:` prefix on the contact token (e.g. `T:C1204`), mapping to `wire_down=True` on `Contact`/`CompareContact`.
|
|
25
25
|
|
|
26
26
|
## Left-edge rendering
|
|
27
27
|
|
|
@@ -21,6 +21,11 @@ from .topology import CELL_SIZE, COLS_PER_ROW
|
|
|
21
21
|
# Instruction data starts at this offset in the cell header.
|
|
22
22
|
_INSTR_DATA_OFFSET = 0x25
|
|
23
23
|
|
|
24
|
+
# Pre-compiled struct for the 37-byte cell header (single pack replaces 8 calls).
|
|
25
|
+
# Layout: pad(1) col(u32) row(u32) span(u8) vis(u8) 0(u8) extra(u8)
|
|
26
|
+
# instr_idx(i32) 1(u32) contact(u32) seg(u32) right(u32) down(u32)
|
|
27
|
+
_HEADER_STRUCT = struct.Struct("<xIIBBBBiIIIII")
|
|
28
|
+
|
|
24
29
|
|
|
25
30
|
# ---------------------------------------------------------------------------
|
|
26
31
|
# Unified cell builder
|
|
@@ -67,37 +72,21 @@ class ClickCell:
|
|
|
67
72
|
row_span: int = 1
|
|
68
73
|
visual_rows: int = 1
|
|
69
74
|
|
|
70
|
-
def build_header(self) ->
|
|
75
|
+
def build_header(self) -> bytes:
|
|
71
76
|
"""Build the 0x25 (37-byte) structured header."""
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
# 32-bit LE Column Index and Row Index
|
|
75
|
-
header[0x01:0x05] = struct.pack("<I", self.col)
|
|
76
|
-
header[0x05:0x09] = struct.pack("<I", self.global_row + 1)
|
|
77
|
-
|
|
78
|
-
# 8-bit structural bytes
|
|
77
|
+
# 8-bit structural bytes at +0x09..+0x0C
|
|
79
78
|
if self.row_span > 1:
|
|
80
79
|
# Multi-row AF instruction (timer): +0x09 = row span,
|
|
81
80
|
# +0x0A = visual sub-rows, +0x0B stays 0x00 (no 0xFD marker).
|
|
82
|
-
|
|
83
|
-
header[0x0A] = self.visual_rows
|
|
81
|
+
b09, b0a, b0c = self.row_span, self.visual_rows, 0
|
|
84
82
|
elif self.blob or self.rung_has_instructions:
|
|
85
83
|
# Instruction cell or wire cell in an instruction-bearing rung.
|
|
86
84
|
# Native Click writes +0x0B=0x00, +0x0C=0x00 for these cells
|
|
87
85
|
# (confirmed via native captures: 1rung_2rows, instr-cond__and).
|
|
88
|
-
|
|
89
|
-
header[0x0A] = 0x01
|
|
86
|
+
b09, b0a, b0c = 1, 1, 0
|
|
90
87
|
else:
|
|
91
88
|
# Pure wire/data cell in a wire-only rung: +0x0C = 0x01
|
|
92
|
-
|
|
93
|
-
header[0x0A] = 0x01
|
|
94
|
-
header[0x0C] = 0x01
|
|
95
|
-
|
|
96
|
-
# 32-bit LE Instruction Index (-1 packs to 0xFFFFFFFF for data cells)
|
|
97
|
-
header[0x0D:0x11] = struct.pack("<i", self.instr_index)
|
|
98
|
-
|
|
99
|
-
# 32-bit LE Structural Flag (always 1)
|
|
100
|
-
header[0x11:0x15] = struct.pack("<I", 1)
|
|
89
|
+
b09, b0a, b0c = 1, 1, 1
|
|
101
90
|
|
|
102
91
|
# 32-bit LE Wire & Logic Flags
|
|
103
92
|
if self.blob:
|
|
@@ -106,12 +95,20 @@ class ClickCell:
|
|
|
106
95
|
contact_flag = self.nop_enable
|
|
107
96
|
right_flag = self.af_nop if self.af_nop else self.wire_right
|
|
108
97
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
98
|
+
return _HEADER_STRUCT.pack(
|
|
99
|
+
self.col,
|
|
100
|
+
self.global_row + 1,
|
|
101
|
+
b09,
|
|
102
|
+
b0a,
|
|
103
|
+
0,
|
|
104
|
+
b0c,
|
|
105
|
+
self.instr_index,
|
|
106
|
+
1,
|
|
107
|
+
contact_flag,
|
|
108
|
+
self.segment,
|
|
109
|
+
right_flag,
|
|
110
|
+
self.wire_down,
|
|
111
|
+
)
|
|
115
112
|
|
|
116
113
|
def build_tail(self) -> bytearray:
|
|
117
114
|
"""Build the 16-byte tail with dynamic rung index."""
|
|
@@ -2,10 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import re
|
|
6
|
+
|
|
5
7
|
MARKER_COLUMN = "marker"
|
|
6
8
|
OUTPUT_COLUMN = "AF"
|
|
7
9
|
COMMENT_MARKER = "#"
|
|
8
10
|
|
|
11
|
+
# Rung-start marker: ``R`` optionally followed by a 1-based decimal index
|
|
12
|
+
# (``R``, ``R1``, ``R2``, ...). The index is decorative and ignored on read.
|
|
13
|
+
_RUNG_MARKER_RE = re.compile(r"R\d*")
|
|
14
|
+
|
|
9
15
|
|
|
10
16
|
def _excel_column_name(index_1_based: int) -> str:
|
|
11
17
|
value = index_1_based
|
|
@@ -21,8 +27,13 @@ CSV_HEADER = (MARKER_COLUMN, *CONDITION_COLUMNS, OUTPUT_COLUMN)
|
|
|
21
27
|
TOTAL_COLUMNS = len(CSV_HEADER)
|
|
22
28
|
|
|
23
29
|
|
|
30
|
+
def is_rung_marker(value: str) -> bool:
|
|
31
|
+
"""Return True for a rung-start marker: ``R`` with optional 1-based index."""
|
|
32
|
+
return _RUNG_MARKER_RE.fullmatch(value) is not None
|
|
33
|
+
|
|
34
|
+
|
|
24
35
|
def is_valid_marker(value: str) -> bool:
|
|
25
|
-
return value in {"
|
|
36
|
+
return value in {"", COMMENT_MARKER} or is_rung_marker(value)
|
|
26
37
|
|
|
27
38
|
|
|
28
39
|
def validate_header(fields: list[str]) -> None:
|
|
@@ -8,7 +8,7 @@ from pathlib import Path
|
|
|
8
8
|
from typing import Literal
|
|
9
9
|
|
|
10
10
|
from .ast import CanonicalRow, ParsedCsvFileAst, RowAst, RungAst
|
|
11
|
-
from .contract import TOTAL_COLUMNS, is_valid_marker, validate_header
|
|
11
|
+
from .contract import TOTAL_COLUMNS, is_rung_marker, is_valid_marker, validate_header
|
|
12
12
|
from .token_parser import parse_af_token, parse_condition_token
|
|
13
13
|
|
|
14
14
|
|
|
@@ -24,7 +24,9 @@ def _detect_file_role(path: Path) -> tuple[Literal["main", "subroutine"], str |
|
|
|
24
24
|
def _canonical_row_from_fields(fields: list[str]) -> CanonicalRow:
|
|
25
25
|
marker = fields[0].strip() if fields else ""
|
|
26
26
|
if not is_valid_marker(marker):
|
|
27
|
-
raise ValueError(
|
|
27
|
+
raise ValueError(
|
|
28
|
+
f"Invalid marker {marker!r}; expected 'R' (optionally indexed, e.g. R1), '#', or blank"
|
|
29
|
+
)
|
|
28
30
|
|
|
29
31
|
# Comment rows may be short (just marker + text); pad to full width.
|
|
30
32
|
# Preserve whitespace in column A for code-style comments (indentation).
|
|
@@ -67,7 +69,7 @@ def _segment_rungs(rows: tuple[RowAst, ...]) -> tuple[RungAst, ...]:
|
|
|
67
69
|
pending_comments.append(row)
|
|
68
70
|
continue
|
|
69
71
|
|
|
70
|
-
if row.canonical.marker
|
|
72
|
+
if is_rung_marker(row.canonical.marker):
|
|
71
73
|
if current:
|
|
72
74
|
rungs.append(RungAst(comment_rows=tuple(current_comments), rows=tuple(current)))
|
|
73
75
|
current = [row]
|
|
@@ -104,13 +104,32 @@ def _append_data_row(
|
|
|
104
104
|
return data_row_count + 1
|
|
105
105
|
|
|
106
106
|
|
|
107
|
+
def _followed_by_floating_row(af_tokens: Sequence[object], span_end: int) -> bool:
|
|
108
|
+
"""True when a blank-AF row sits just below a tall instruction's span.
|
|
109
|
+
|
|
110
|
+
Such a row would be absorbed into the instruction's continuation slots on
|
|
111
|
+
reparse, so the instruction's trailing padding must stay positional rather
|
|
112
|
+
than dehydrated — otherwise the following content floats up. A real AF
|
|
113
|
+
instruction (or the end of the rung) anchors the position, so dehydration
|
|
114
|
+
is safe there.
|
|
115
|
+
"""
|
|
116
|
+
return span_end < len(af_tokens) and af_tokens[span_end] == ""
|
|
117
|
+
|
|
118
|
+
|
|
107
119
|
def _emit_blank_continuation(
|
|
108
120
|
rows: list[list[str]],
|
|
109
121
|
data_row_count: int,
|
|
110
122
|
conditions: Sequence[object],
|
|
123
|
+
keep_positional: bool = False,
|
|
111
124
|
) -> int:
|
|
112
|
-
"""Emit a blank-AF continuation row
|
|
113
|
-
|
|
125
|
+
"""Emit a blank-AF continuation row.
|
|
126
|
+
|
|
127
|
+
Trailing padding (blank cells and ``|`` pass-through wires) is dehydrated —
|
|
128
|
+
the reparser rebuilds it from the instruction's visual height. But when a
|
|
129
|
+
blank-AF row follows the instruction's span (``keep_positional``), the row
|
|
130
|
+
is emitted so following content keeps its position on reparse.
|
|
131
|
+
"""
|
|
132
|
+
if not keep_positional and _is_padding_row(conditions):
|
|
114
133
|
return data_row_count
|
|
115
134
|
return _append_data_row(rows, data_row_count, conditions, "")
|
|
116
135
|
|
|
@@ -139,13 +158,16 @@ def _emit_timer_block(
|
|
|
139
158
|
message="timer continuation row must be blank AF",
|
|
140
159
|
)
|
|
141
160
|
|
|
161
|
+
keep = _followed_by_floating_row(af_tokens, start + 2)
|
|
142
162
|
data_row_count = _append_data_row(rows, data_row_count, condition_rows[start], timer)
|
|
143
163
|
if timer.retained:
|
|
144
164
|
data_row_count = _append_data_row(
|
|
145
165
|
rows, data_row_count, condition_rows[start + 1], ".reset()"
|
|
146
166
|
)
|
|
147
167
|
else:
|
|
148
|
-
data_row_count = _emit_blank_continuation(
|
|
168
|
+
data_row_count = _emit_blank_continuation(
|
|
169
|
+
rows, data_row_count, condition_rows[start + 1], keep
|
|
170
|
+
)
|
|
149
171
|
return data_row_count, 2
|
|
150
172
|
|
|
151
173
|
|
|
@@ -164,6 +186,7 @@ def _emit_counter_block(
|
|
|
164
186
|
f"{counter.counter_type} requires {needed} decoded rows; got {len(condition_rows)}"
|
|
165
187
|
)
|
|
166
188
|
|
|
189
|
+
keep = _followed_by_floating_row(af_tokens, start + 3)
|
|
167
190
|
if counter.counter_type == "count_up":
|
|
168
191
|
_require_blank_af(
|
|
169
192
|
af_tokens[start + 1],
|
|
@@ -180,7 +203,7 @@ def _emit_counter_block(
|
|
|
180
203
|
)
|
|
181
204
|
else:
|
|
182
205
|
data_row_count = _emit_blank_continuation(
|
|
183
|
-
rows, data_row_count, condition_rows[start + 1]
|
|
206
|
+
rows, data_row_count, condition_rows[start + 1], keep
|
|
184
207
|
)
|
|
185
208
|
if counter.reset_enabled:
|
|
186
209
|
data_row_count = _append_data_row(
|
|
@@ -188,7 +211,7 @@ def _emit_counter_block(
|
|
|
188
211
|
)
|
|
189
212
|
else:
|
|
190
213
|
data_row_count = _emit_blank_continuation(
|
|
191
|
-
rows, data_row_count, condition_rows[start + 2]
|
|
214
|
+
rows, data_row_count, condition_rows[start + 2], keep
|
|
192
215
|
)
|
|
193
216
|
return data_row_count, 3
|
|
194
217
|
|
|
@@ -212,7 +235,9 @@ def _emit_counter_block(
|
|
|
212
235
|
rows, data_row_count, condition_rows[start + 2], ".reset()"
|
|
213
236
|
)
|
|
214
237
|
else:
|
|
215
|
-
data_row_count = _emit_blank_continuation(
|
|
238
|
+
data_row_count = _emit_blank_continuation(
|
|
239
|
+
rows, data_row_count, condition_rows[start + 2], keep
|
|
240
|
+
)
|
|
216
241
|
return data_row_count, 3
|
|
217
242
|
|
|
218
243
|
|
|
@@ -270,6 +295,7 @@ def _emit_drum_block(
|
|
|
270
295
|
message="drum .jog() row must be blank AF",
|
|
271
296
|
)
|
|
272
297
|
|
|
298
|
+
keep = _followed_by_floating_row(af_tokens, start + 4)
|
|
273
299
|
data_row_count = _append_data_row(rows, data_row_count, condition_rows[start], drum)
|
|
274
300
|
data_row_count = _append_data_row(rows, data_row_count, condition_rows[start + 1], ".reset()")
|
|
275
301
|
if drum.jump_enabled:
|
|
@@ -280,11 +306,15 @@ def _emit_drum_block(
|
|
|
280
306
|
f".jump({drum.jump_target})",
|
|
281
307
|
)
|
|
282
308
|
else:
|
|
283
|
-
data_row_count = _emit_blank_continuation(
|
|
309
|
+
data_row_count = _emit_blank_continuation(
|
|
310
|
+
rows, data_row_count, condition_rows[start + 2], keep
|
|
311
|
+
)
|
|
284
312
|
if drum.jog_enabled:
|
|
285
313
|
data_row_count = _append_data_row(rows, data_row_count, condition_rows[start + 3], ".jog()")
|
|
286
314
|
else:
|
|
287
|
-
data_row_count = _emit_blank_continuation(
|
|
315
|
+
data_row_count = _emit_blank_continuation(
|
|
316
|
+
rows, data_row_count, condition_rows[start + 3], keep
|
|
317
|
+
)
|
|
288
318
|
return data_row_count, 4
|
|
289
319
|
|
|
290
320
|
|
|
@@ -304,6 +334,7 @@ def _emit_generic_tall_block(
|
|
|
304
334
|
f"{type(af).__name__} requires {needed} decoded rows; got {len(condition_rows)}"
|
|
305
335
|
)
|
|
306
336
|
|
|
337
|
+
keep = _followed_by_floating_row(af_tokens, start + visual_rows)
|
|
307
338
|
data_row_count = _append_data_row(rows, data_row_count, condition_rows[start], af)
|
|
308
339
|
for offset in range(1, visual_rows):
|
|
309
340
|
_require_blank_af(
|
|
@@ -311,7 +342,7 @@ def _emit_generic_tall_block(
|
|
|
311
342
|
message=f"{type(af).__name__} continuation row must be blank AF",
|
|
312
343
|
)
|
|
313
344
|
data_row_count = _emit_blank_continuation(
|
|
314
|
-
rows, data_row_count, condition_rows[start + offset]
|
|
345
|
+
rows, data_row_count, condition_rows[start + offset], keep
|
|
315
346
|
)
|
|
316
347
|
return data_row_count, visual_rows
|
|
317
348
|
|
|
@@ -498,6 +529,8 @@ def decoded_rung_to_rows(rung: Rung) -> list[list[str]]:
|
|
|
498
529
|
def write_csv(
|
|
499
530
|
path: Path | str,
|
|
500
531
|
rungs: list[Rung],
|
|
532
|
+
*,
|
|
533
|
+
index: bool = False,
|
|
501
534
|
) -> None:
|
|
502
535
|
"""Write decoded rungs to a canonical CSV file.
|
|
503
536
|
|
|
@@ -508,6 +541,12 @@ def write_csv(
|
|
|
508
541
|
rungs:
|
|
509
542
|
One or more decoded rungs (from ``decode_rung()`` or
|
|
510
543
|
``decode_rungs()``).
|
|
544
|
+
index:
|
|
545
|
+
When ``True``, the per-rung ``R`` marker is replaced with a 1-based
|
|
546
|
+
sequential index (``R1``, ``R2``, ``R3``, ...) counting across the
|
|
547
|
+
whole file. The default (``False``) emits a plain ``R``. Indexed
|
|
548
|
+
files still round-trip through ``read_csv()`` — the digits are
|
|
549
|
+
decorative and ignored on read.
|
|
511
550
|
|
|
512
551
|
Raises
|
|
513
552
|
------
|
|
@@ -518,6 +557,8 @@ def write_csv(
|
|
|
518
557
|
with open(path, "w", newline="", encoding="utf-8") as f:
|
|
519
558
|
writer = csv_mod.writer(f)
|
|
520
559
|
writer.writerow(CSV_HEADER)
|
|
521
|
-
for rung in rungs:
|
|
560
|
+
for rung_number, rung in enumerate(rungs, start=1): # start=1 → first rung is R1
|
|
522
561
|
for row in decoded_rung_to_rows(rung):
|
|
562
|
+
if index and row and row[0] == "R":
|
|
563
|
+
row = [f"R{rung_number}", *row[1:]]
|
|
523
564
|
writer.writerow(row)
|