laddercodec 0.2.2__tar.gz → 0.3.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.
Files changed (635) hide show
  1. {laddercodec-0.2.2 → laddercodec-0.3.0}/AGENTS.md +8 -2
  2. {laddercodec-0.2.2 → laddercodec-0.3.0}/CHANGELOG.md +24 -0
  3. {laddercodec-0.2.2 → laddercodec-0.3.0}/PKG-INFO +1 -1
  4. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/dump_scr_tags.py +2 -1
  5. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/gen_reference.py +13 -1
  6. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/guides/adding-instructions.md +64 -4
  7. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/guides/csv-format.md +36 -1
  8. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/guides/decoding.md +21 -2
  9. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/guides/encoding.md +1 -1
  10. laddercodec-0.3.0/docs/internals/instruction-blobs.md +206 -0
  11. laddercodec-0.3.0/scratchpad/click-v4/captures/.gitignore +2 -0
  12. laddercodec-0.3.0/scratchpad/click-v4/captures/README.md +61 -0
  13. laddercodec-0.3.0/scratchpad/click-v4/captures/drum_fix_stubs.py +84 -0
  14. laddercodec-0.3.0/scratchpad/click-v4/captures/expected/drum.csv +40 -0
  15. laddercodec-0.3.0/scratchpad/click-v4/captures/expected/loop.csv +105 -0
  16. laddercodec-0.3.0/scratchpad/click-v4/captures/expected/math.csv +70 -0
  17. laddercodec-0.3.0/scratchpad/click-v4/captures/expected/out.csv +55 -0
  18. laddercodec-0.3.0/scratchpad/click-v4/captures/expected/pins.csv +56 -0
  19. laddercodec-0.3.0/scratchpad/click-v4/captures/math_edge_stubs.py +175 -0
  20. laddercodec-0.3.0/scratchpad/click-v4/captures/stubs/drum.csv +40 -0
  21. laddercodec-0.3.0/scratchpad/click-v4/captures/stubs/drum_fix.csv +118 -0
  22. laddercodec-0.3.0/scratchpad/click-v4/captures/stubs/drum_fix_te.csv +60 -0
  23. laddercodec-0.3.0/scratchpad/click-v4/captures/stubs/loop.csv +105 -0
  24. laddercodec-0.3.0/scratchpad/click-v4/captures/stubs/math.csv +70 -0
  25. laddercodec-0.3.0/scratchpad/click-v4/captures/stubs/math_edge.csv +92 -0
  26. laddercodec-0.3.0/scratchpad/click-v4/captures/stubs/math_neg2.csv +26 -0
  27. laddercodec-0.3.0/scratchpad/click-v4/captures/stubs/math_operands.csv +65 -0
  28. laddercodec-0.3.0/scratchpad/click-v4/captures/stubs/math_wide.csv +14 -0
  29. laddercodec-0.3.0/scratchpad/click-v4/captures/stubs/out.csv +55 -0
  30. laddercodec-0.3.0/scratchpad/click-v4/captures/stubs/pins.csv +47 -0
  31. laddercodec-0.3.0/scratchpad/click-v4/captures/v4_capture.py +539 -0
  32. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/__init__.py +9 -0
  33. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/_grid.py +1 -1
  34. laddercodec-0.3.0/src/laddercodec/compat.py +64 -0
  35. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/csv/converter.py +172 -314
  36. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/csv/writer.py +100 -200
  37. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/decode.py +6 -6
  38. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/decode_program.py +54 -19
  39. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/__init__.py +21 -4
  40. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/coil.py +6 -0
  41. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/counter.py +33 -5
  42. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/drum.py +184 -31
  43. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/forloop.py +78 -11
  44. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/math.py +124 -35
  45. laddercodec-0.3.0/src/laddercodec/instructions/out_variant.py +269 -0
  46. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/raw.py +3 -2
  47. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/shift.py +18 -6
  48. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/timer.py +18 -5
  49. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/model.py +42 -2
  50. laddercodec-0.3.0/tests/__init__.py +0 -0
  51. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/csv/test_converter.py +110 -0
  52. laddercodec-0.3.0/tests/csv/test_pinned_or_inputs.py +289 -0
  53. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/csv/test_writer.py +2 -1
  54. laddercodec-0.3.0/tests/fixtures/coverage/golden/drum__v4.bin +0 -0
  55. laddercodec-0.3.0/tests/fixtures/coverage/golden/drum__v4.csv +40 -0
  56. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/event_drum__jog.bin +0 -0
  57. laddercodec-0.3.0/tests/fixtures/coverage/golden/loop__v4.bin +0 -0
  58. laddercodec-0.3.0/tests/fixtures/coverage/golden/loop__v4.csv +105 -0
  59. laddercodec-0.3.0/tests/fixtures/coverage/golden/math__negative.bin +0 -0
  60. laddercodec-0.3.0/tests/fixtures/coverage/golden/math__negative.csv +58 -0
  61. laddercodec-0.3.0/tests/fixtures/coverage/golden/math__v4.bin +0 -0
  62. laddercodec-0.3.0/tests/fixtures/coverage/golden/math__v4.csv +70 -0
  63. laddercodec-0.3.0/tests/fixtures/coverage/golden/out__v4.bin +0 -0
  64. laddercodec-0.3.0/tests/fixtures/coverage/golden/out__v4.csv +55 -0
  65. laddercodec-0.3.0/tests/fixtures/coverage/golden/pins__v4.bin +0 -0
  66. laddercodec-0.3.0/tests/fixtures/coverage/golden/pins__v4.csv +56 -0
  67. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/verify_progress.log +7 -1
  68. laddercodec-0.3.0/tests/fixtures/pinned_or/conf_counters_count_down.csv +22 -0
  69. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/README.md +2 -0
  70. laddercodec-0.3.0/tests/fixtures/scr_captures/pins.scr +0 -0
  71. laddercodec-0.3.0/tests/fixtures/v4_captures/drum.bin +0 -0
  72. laddercodec-0.3.0/tests/fixtures/v4_captures/drum_jog.bin +0 -0
  73. laddercodec-0.3.0/tests/fixtures/v4_captures/loop_exits.bin +0 -0
  74. laddercodec-0.3.0/tests/fixtures/v4_captures/math.bin +0 -0
  75. laddercodec-0.3.0/tests/fixtures/v4_captures/math_typed.bin +0 -0
  76. laddercodec-0.3.0/tests/fixtures/v4_captures/out.bin +0 -0
  77. laddercodec-0.3.0/tests/fixtures/v4_captures/out_debounce_example.bin +0 -0
  78. laddercodec-0.3.0/tests/fixtures/v4_captures/pins.bin +0 -0
  79. laddercodec-0.3.0/tests/fixtures/v4_captures/retyped/math_neg.bin +0 -0
  80. laddercodec-0.3.0/tests/fixtures/v4_captures/retyped/math_wide.bin +0 -0
  81. laddercodec-0.3.0/tests/fixtures/v4_captures/retyped/math_xd.bin +0 -0
  82. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_decode_program.py +27 -0
  83. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_forloop.py +25 -1
  84. laddercodec-0.3.0/tests/ladder/test_math.py +147 -0
  85. laddercodec-0.3.0/tests/test_compat.py +75 -0
  86. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/test_public_api.py +5 -0
  87. laddercodec-0.3.0/tests/test_v4_captures.py +326 -0
  88. laddercodec-0.2.2/docs/internals/instruction-blobs.md +0 -69
  89. laddercodec-0.2.2/tests/ladder/test_math.py +0 -43
  90. {laddercodec-0.2.2 → laddercodec-0.3.0}/.claude/settings.local.json +0 -0
  91. {laddercodec-0.2.2 → laddercodec-0.3.0}/.github/scripts/check_public_site.py +0 -0
  92. {laddercodec-0.2.2 → laddercodec-0.3.0}/.github/scripts/prune_public_site.py +0 -0
  93. {laddercodec-0.2.2 → laddercodec-0.3.0}/.github/workflows/ci.yml +0 -0
  94. {laddercodec-0.2.2 → laddercodec-0.3.0}/.github/workflows/docs.yml +0 -0
  95. {laddercodec-0.2.2 → laddercodec-0.3.0}/.github/workflows/publish.yml +0 -0
  96. {laddercodec-0.2.2 → laddercodec-0.3.0}/.gitignore +0 -0
  97. {laddercodec-0.2.2 → laddercodec-0.3.0}/CLAUDE.md +0 -0
  98. {laddercodec-0.2.2 → laddercodec-0.3.0}/LICENSE +0 -0
  99. {laddercodec-0.2.2 → laddercodec-0.3.0}/Makefile +0 -0
  100. {laddercodec-0.2.2 → laddercodec-0.3.0}/README.md +0 -0
  101. {laddercodec-0.2.2 → laddercodec-0.3.0}/add-features-workflow.md +0 -0
  102. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/analyze_scr.py +0 -0
  103. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/combine_coverage.py +0 -0
  104. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/compare_blobs.py +0 -0
  105. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/compare_csv.py +0 -0
  106. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/coverage_golden.py +0 -0
  107. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/create_mr_max_csv.py +0 -0
  108. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/diag_blob.py +0 -0
  109. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/gen_modbus_coverage.py +0 -0
  110. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/golden.py +0 -0
  111. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/inspect_bin.py +0 -0
  112. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/inspect_scr.py +0 -0
  113. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/lint.py +0 -0
  114. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/pdf_to_png.py +0 -0
  115. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/test_decode_scr.py +0 -0
  116. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/validate_scr.py +0 -0
  117. {laddercodec-0.2.2 → laddercodec-0.3.0}/devtools/walk_scr.py +0 -0
  118. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/AGENTS.md +0 -0
  119. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/CLAUDE.md +0 -0
  120. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/gen_llms.py +0 -0
  121. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/guides/troubleshooting.md +0 -0
  122. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/index.md +0 -0
  123. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/internals/binary-format.md +0 -0
  124. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/internals/wire-rendering.md +0 -0
  125. {laddercodec-0.2.2 → laddercodec-0.3.0}/docs/stylesheets/extra.css +0 -0
  126. {laddercodec-0.2.2 → laddercodec-0.3.0}/mkdocs.yml +0 -0
  127. {laddercodec-0.2.2 → laddercodec-0.3.0}/pyproject.toml +0 -0
  128. /laddercodec-0.2.2/tests/__init__.py → /laddercodec-0.3.0/scratchpad/click-v4/captures/copyback/.gitkeep +0 -0
  129. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/binary_helpers.py +0 -0
  130. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/cell.py +0 -0
  131. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/csv/__init__.py +0 -0
  132. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/csv/ast.py +0 -0
  133. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/csv/bundle.py +0 -0
  134. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/csv/contract.py +0 -0
  135. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/csv/parser.py +0 -0
  136. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/csv/token_parser.py +0 -0
  137. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/empty_multirow.py +0 -0
  138. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/encode.py +0 -0
  139. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/encode_multi.py +0 -0
  140. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/call.py +0 -0
  141. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/comparison.py +0 -0
  142. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/contact.py +0 -0
  143. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/copy.py +0 -0
  144. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/email.py +0 -0
  145. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/end.py +0 -0
  146. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/family.py +0 -0
  147. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/home.py +0 -0
  148. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/position.py +0 -0
  149. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/return_.py +0 -0
  150. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/search.py +0 -0
  151. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/send_receive.py +0 -0
  152. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/instructions/velocity.py +0 -0
  153. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/resources/empty_multirow_rule_minimal.scaffold.bin +0 -0
  154. {laddercodec-0.2.2 → laddercodec-0.3.0}/src/laddercodec/topology.py +0 -0
  155. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/csv/test_bundle.py +0 -0
  156. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/csv/test_contract.py +0 -0
  157. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/csv/test_parser.py +0 -0
  158. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/csv/test_token_parser.py +0 -0
  159. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/csv/test_writer_raw_validator.py +0 -0
  160. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/coverage.ckp +0 -0
  161. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/blockcopy__block.bin +0 -0
  162. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/blockcopy__block.csv +0 -0
  163. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/blockcopy__oneshot.bin +0 -0
  164. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/blockcopy__oneshot.csv +0 -0
  165. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/blockcopy__to_ascii.bin +0 -0
  166. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/blockcopy__to_ascii.csv +0 -0
  167. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/blockcopy__to_value.bin +0 -0
  168. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/blockcopy__to_value.csv +0 -0
  169. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/call__basic.bin +0 -0
  170. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/call__basic.csv +0 -0
  171. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__and.bin +0 -0
  172. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__and.csv +0 -0
  173. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__eq.bin +0 -0
  174. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__eq.csv +0 -0
  175. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__fall.bin +0 -0
  176. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__fall.csv +0 -0
  177. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__ge.bin +0 -0
  178. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__ge.csv +0 -0
  179. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__gt.bin +0 -0
  180. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__gt.csv +0 -0
  181. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__immediate.bin +0 -0
  182. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__immediate.csv +0 -0
  183. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__le.bin +0 -0
  184. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__le.csv +0 -0
  185. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__lt.bin +0 -0
  186. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__lt.csv +0 -0
  187. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__nc.bin +0 -0
  188. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__nc.csv +0 -0
  189. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__ne.bin +0 -0
  190. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__ne.csv +0 -0
  191. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__no.bin +0 -0
  192. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__no.csv +0 -0
  193. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__or.bin +0 -0
  194. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__or.csv +0 -0
  195. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__rise.bin +0 -0
  196. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/cond__rise.csv +0 -0
  197. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__literal_float.bin +0 -0
  198. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__literal_float.csv +0 -0
  199. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__literal_int.bin +0 -0
  200. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__literal_int.csv +0 -0
  201. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__oneshot.bin +0 -0
  202. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__oneshot.csv +0 -0
  203. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__tag.bin +0 -0
  204. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__tag.csv +0 -0
  205. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_ascii.bin +0 -0
  206. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_ascii.csv +0 -0
  207. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_binary.bin +0 -0
  208. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_binary.csv +0 -0
  209. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_text.bin +0 -0
  210. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_text.csv +0 -0
  211. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_text_exp.bin +0 -0
  212. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_text_exp.csv +0 -0
  213. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_text_sz.bin +0 -0
  214. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_text_sz.csv +0 -0
  215. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_text_term.bin +0 -0
  216. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_text_term.csv +0 -0
  217. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_value.bin +0 -0
  218. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/copy__to_value.csv +0 -0
  219. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/count_down.bin +0 -0
  220. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/count_down.csv +0 -0
  221. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/count_up__down.bin +0 -0
  222. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/count_up__down.csv +0 -0
  223. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/count_up__reset.bin +0 -0
  224. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/count_up__reset.csv +0 -0
  225. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/end.bin +0 -0
  226. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/end.csv +0 -0
  227. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/event_drum__basic.bin +0 -0
  228. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/event_drum__basic.csv +0 -0
  229. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/event_drum__full.bin +0 -0
  230. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/event_drum__full.csv +0 -0
  231. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/event_drum__jog.csv +0 -0
  232. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/event_drum__jump.bin +0 -0
  233. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/event_drum__jump.csv +0 -0
  234. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/event_drum__max.bin +0 -0
  235. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/event_drum__max.csv +0 -0
  236. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/fill__literal.bin +0 -0
  237. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/fill__literal.csv +0 -0
  238. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/fill__oneshot.bin +0 -0
  239. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/fill__oneshot.csv +0 -0
  240. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/fill__tag.bin +0 -0
  241. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/fill__tag.csv +0 -0
  242. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/forloop__basic.bin +0 -0
  243. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/forloop__basic.csv +0 -0
  244. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/forloop__oneshot.bin +0 -0
  245. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/forloop__oneshot.csv +0 -0
  246. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/latch__block.bin +0 -0
  247. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/latch__block.csv +0 -0
  248. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/latch__immediate.bin +0 -0
  249. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/latch__immediate.csv +0 -0
  250. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/latch__tag.bin +0 -0
  251. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/latch__tag.csv +0 -0
  252. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/math__decimal.bin +0 -0
  253. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/math__decimal.csv +0 -0
  254. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/math__hex.bin +0 -0
  255. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/math__hex.csv +0 -0
  256. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/math__oneshot.bin +0 -0
  257. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/math__oneshot.csv +0 -0
  258. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/off_delay__tof.bin +0 -0
  259. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/off_delay__tof.csv +0 -0
  260. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/on_delay__rton.bin +0 -0
  261. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/on_delay__rton.csv +0 -0
  262. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/on_delay__ton.bin +0 -0
  263. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/on_delay__ton.csv +0 -0
  264. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/out__block.bin +0 -0
  265. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/out__block.csv +0 -0
  266. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/out__immediate.bin +0 -0
  267. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/out__immediate.csv +0 -0
  268. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/out__oneshot.bin +0 -0
  269. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/out__oneshot.csv +0 -0
  270. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/out__tag.bin +0 -0
  271. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/out__tag.csv +0 -0
  272. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_bits.bin +0 -0
  273. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_bits.csv +0 -0
  274. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_bits__oneshot.bin +0 -0
  275. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_bits__oneshot.csv +0 -0
  276. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_text.bin +0 -0
  277. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_text.csv +0 -0
  278. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_text__allow_whitespace.bin +0 -0
  279. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_text__allow_whitespace.csv +0 -0
  280. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_text__oneshot.bin +0 -0
  281. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_text__oneshot.csv +0 -0
  282. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_words.bin +0 -0
  283. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_words.csv +0 -0
  284. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_words__oneshot.bin +0 -0
  285. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/pack_words__oneshot.csv +0 -0
  286. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/raw_instructions__email.bin +0 -0
  287. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/raw_instructions__email.csv +0 -0
  288. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/raw_instructions__home.bin +0 -0
  289. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/raw_instructions__home.csv +0 -0
  290. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/raw_instructions__position.bin +0 -0
  291. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/raw_instructions__position.csv +0 -0
  292. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/raw_instructions__velocity.bin +0 -0
  293. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/raw_instructions__velocity.csv +0 -0
  294. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__rtu_click_block.bin +0 -0
  295. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__rtu_click_block.csv +0 -0
  296. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__rtu_click_single.bin +0 -0
  297. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__rtu_click_single.csv +0 -0
  298. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__rtu_modbus_block.bin +0 -0
  299. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__rtu_modbus_block.csv +0 -0
  300. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__rtu_modbus_single.bin +0 -0
  301. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__rtu_modbus_single.csv +0 -0
  302. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__tcp_click_coil.bin +0 -0
  303. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__tcp_click_coil.csv +0 -0
  304. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__tcp_click_input.bin +0 -0
  305. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__tcp_click_input.csv +0 -0
  306. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__tcp_click_input_reg.bin +0 -0
  307. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__tcp_click_input_reg.csv +0 -0
  308. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__tcp_click_wordswap.bin +0 -0
  309. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/receive__tcp_click_wordswap.csv +0 -0
  310. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/reset__block.bin +0 -0
  311. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/reset__block.csv +0 -0
  312. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/reset__immediate.bin +0 -0
  313. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/reset__immediate.csv +0 -0
  314. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/reset__tag.bin +0 -0
  315. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/reset__tag.csv +0 -0
  316. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/return_early__basic.bin +0 -0
  317. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/return_early__basic.csv +0 -0
  318. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__continuous.bin +0 -0
  319. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__continuous.csv +0 -0
  320. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__eq.bin +0 -0
  321. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__eq.csv +0 -0
  322. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__ge.bin +0 -0
  323. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__ge.csv +0 -0
  324. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__gt.bin +0 -0
  325. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__gt.csv +0 -0
  326. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__le.bin +0 -0
  327. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__le.csv +0 -0
  328. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__lt.bin +0 -0
  329. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__lt.csv +0 -0
  330. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__ne.bin +0 -0
  331. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__ne.csv +0 -0
  332. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__oneshot.bin +0 -0
  333. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/search__oneshot.csv +0 -0
  334. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__error_off.bin +0 -0
  335. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__error_off.csv +0 -0
  336. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__errorcode_off.bin +0 -0
  337. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__errorcode_off.csv +0 -0
  338. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__rtu_click_block.bin +0 -0
  339. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__rtu_click_block.csv +0 -0
  340. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__rtu_click_single.bin +0 -0
  341. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__rtu_click_single.csv +0 -0
  342. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__rtu_modbus_block.bin +0 -0
  343. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__rtu_modbus_block.csv +0 -0
  344. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__rtu_modbus_single.bin +0 -0
  345. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__rtu_modbus_single.csv +0 -0
  346. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__sending_off.bin +0 -0
  347. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__sending_off.csv +0 -0
  348. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__success_off.bin +0 -0
  349. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__success_off.csv +0 -0
  350. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__tcp_click_coil.bin +0 -0
  351. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__tcp_click_coil.csv +0 -0
  352. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__tcp_click_coils.bin +0 -0
  353. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__tcp_click_coils.csv +0 -0
  354. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__tcp_click_wordswap.bin +0 -0
  355. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/send__tcp_click_wordswap.csv +0 -0
  356. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/shift__basic.bin +0 -0
  357. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/shift__basic.csv +0 -0
  358. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/time_drum__basic.bin +0 -0
  359. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/time_drum__basic.csv +0 -0
  360. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/time_drum__basic_td.bin +0 -0
  361. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/time_drum__basic_td.csv +0 -0
  362. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/unpack_to_bits.bin +0 -0
  363. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/unpack_to_bits.csv +0 -0
  364. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/unpack_to_bits__oneshot.bin +0 -0
  365. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/unpack_to_bits__oneshot.csv +0 -0
  366. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/unpack_to_words.bin +0 -0
  367. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/unpack_to_words.csv +0 -0
  368. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/unpack_to_words__oneshot.bin +0 -0
  369. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/golden/unpack_to_words__oneshot.csv +0 -0
  370. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/coverage/subroutines/coverage_sub.csv +0 -0
  371. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/drum_weird_branch.bin +0 -0
  372. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-1row-fullwire-nop.bin +0 -0
  373. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-1row-fullwire-nop.csv +0 -0
  374. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-1row-max1400.bin +0 -0
  375. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-1row-max1400.csv +0 -0
  376. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-1row-styled-mixed.bin +0 -0
  377. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-1row-styled-mixed.csv +0 -0
  378. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-2row-max1324.bin +0 -0
  379. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-2row-max1324.csv +0 -0
  380. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-2row-nop-wire.bin +0 -0
  381. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-2row-nop-wire.csv +0 -0
  382. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-32row-sparse.bin +0 -0
  383. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-32row-sparse.csv +0 -0
  384. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-3row-mixed.bin +0 -0
  385. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/cmt-3row-mixed.csv +0 -0
  386. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-2row-cond__and.bin +0 -0
  387. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-2row-cond__and.csv +0 -0
  388. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-2row-r0only.bin +0 -0
  389. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-2row-r0only.csv +0 -0
  390. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-2row-spread.bin +0 -0
  391. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-2row-spread.csv +0 -0
  392. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-3row-branch.bin +0 -0
  393. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-3row-branch.csv +0 -0
  394. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-3row-or-colA.bin +0 -0
  395. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-3row-or-colA.csv +0 -0
  396. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-3row-or.bin +0 -0
  397. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-3row-or.csv +0 -0
  398. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-3row-scatter.bin +0 -0
  399. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-3row-scatter.csv +0 -0
  400. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-6row-multi-output.bin +0 -0
  401. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-6row-multi-output.csv +0 -0
  402. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-coil-timer-ret.bin +0 -0
  403. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-coil-timer-ret.csv +0 -0
  404. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-compare-ge.bin +0 -0
  405. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-compare-ge.csv +0 -0
  406. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-compare-series.bin +0 -0
  407. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-compare-series.csv +0 -0
  408. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-compare-timer.bin +0 -0
  409. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-compare-timer.csv +0 -0
  410. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-cond__and.bin +0 -0
  411. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-cond__and.csv +0 -0
  412. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-copy-multirow-2af-T.bin +0 -0
  413. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-copy-multirow-2af-T.csv +0 -0
  414. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-copy-multirow-2af.bin +0 -0
  415. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-copy-multirow-2af.csv +0 -0
  416. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-count_down-row0-data.bin +0 -0
  417. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-count_down-row0-data.csv +0 -0
  418. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-no-out.bin +0 -0
  419. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-no-out.csv +0 -0
  420. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-series.bin +0 -0
  421. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-series.csv +0 -0
  422. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-timer-off.bin +0 -0
  423. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-timer-off.csv +0 -0
  424. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-timer-on.bin +0 -0
  425. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-timer-on.csv +0 -0
  426. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-timer-ret.bin +0 -0
  427. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/instr-timer-ret.csv +0 -0
  428. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-2rung-2row.bin +0 -0
  429. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-2rung-2row.csv +0 -0
  430. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-2rung-wire.bin +0 -0
  431. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-2rung-wire.csv +0 -0
  432. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-3rung-wire-nop.bin +0 -0
  433. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-3rung-wire-nop.csv +0 -0
  434. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-2rung-2row.bin +0 -0
  435. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-2rung-2row.csv +0 -0
  436. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-2rung-both.bin +0 -0
  437. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-2rung-both.csv +0 -0
  438. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-2rung-r1-max1400.bin +0 -0
  439. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-2rung-r1-max1400.csv +0 -0
  440. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-all.bin +0 -0
  441. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-all.csv +0 -0
  442. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-multirow-multiinstructions.bin +0 -0
  443. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-multirow-multiinstructions.csv +0 -0
  444. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-multirow-nopaddedrows.bin +0 -0
  445. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-multirow-nopaddedrows.csv +0 -0
  446. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-multirow.bin +0 -0
  447. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-cmt-3rung-multirow.csv +0 -0
  448. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-instr-2rung.bin +0 -0
  449. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-instr-2rung.csv +0 -0
  450. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-instr-cond__and.bin +0 -0
  451. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/mr-instr-cond__and.csv +0 -0
  452. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/nc-1row-empty.bin +0 -0
  453. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/nc-1row-empty.csv +0 -0
  454. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/nc-1row-fullwire-nop.bin +0 -0
  455. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/nc-1row-fullwire-nop.csv +0 -0
  456. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/nc-32row-empty.bin +0 -0
  457. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/nc-32row-empty.csv +0 -0
  458. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/nc-3row-t-junction.bin +0 -0
  459. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/nc-3row-t-junction.csv +0 -0
  460. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/nc-4row-vertical.bin +0 -0
  461. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/nc-4row-vertical.csv +0 -0
  462. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/ladder_captures/golden/verify_progress.log +0 -0
  463. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/counter_scr.bin +0 -0
  464. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/counter_scr.csv +0 -0
  465. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/counter_scr.scr +0 -0
  466. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/coverage.bin +0 -0
  467. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/coverage.csv +0 -0
  468. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/coverage.scr +0 -0
  469. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/or_topology.bin +0 -0
  470. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/or_topology.csv +0 -0
  471. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/or_topology.scr +0 -0
  472. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/shift_scr.bin +0 -0
  473. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/shift_scr.csv +0 -0
  474. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/shift_scr.scr +0 -0
  475. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/time_drum_b_column.bin +0 -0
  476. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/time_drum_b_column.csv +0 -0
  477. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/time_drum_b_column.scr +0 -0
  478. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/time_drum_insert_rows.bin +0 -0
  479. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/time_drum_insert_rows.csv +0 -0
  480. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/time_drum_insert_rows.png +0 -0
  481. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/time_drum_insert_rows.scr +0 -0
  482. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/time_drums.bin +0 -0
  483. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/time_drums.csv +0 -0
  484. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/scr_captures/time_drums.scr +0 -0
  485. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/main.clipboard.bin +0 -0
  486. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/main.clipboard.csv +0 -0
  487. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/main.csv +0 -0
  488. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/main.scr +0 -0
  489. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AckAlarm.clipboard.bin +0 -0
  490. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AckAlarm.clipboard.csv +0 -0
  491. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AckAlarm.csv +0 -0
  492. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AckAlarm.scr +0 -0
  493. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AckAndClearAllAlarms.clipboard.bin +0 -0
  494. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AckAndClearAllAlarms.clipboard.csv +0 -0
  495. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AckAndClearAllAlarms.csv +0 -0
  496. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AckAndClearAllAlarms.scr +0 -0
  497. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AckWarning.clipboard.bin +0 -0
  498. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AckWarning.clipboard.csv +0 -0
  499. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AckWarning.csv +0 -0
  500. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AckWarning.scr +0 -0
  501. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AlmHistorian.clipboard.bin +0 -0
  502. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AlmHistorian.clipboard.csv +0 -0
  503. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AlmHistorian.csv +0 -0
  504. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/AlmHistorian.scr +0 -0
  505. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Blower.clipboard.bin +0 -0
  506. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Blower.clipboard.csv +0 -0
  507. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Blower.csv +0 -0
  508. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Blower.scr +0 -0
  509. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/DisableOutputs.clipboard.bin +0 -0
  510. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/DisableOutputs.clipboard.csv +0 -0
  511. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/DisableOutputs.csv +0 -0
  512. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/DisableOutputs.scr +0 -0
  513. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Heat.clipboard.bin +0 -0
  514. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Heat.clipboard.csv +0 -0
  515. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Heat.csv +0 -0
  516. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Heat.scr +0 -0
  517. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Init.clipboard.bin +0 -0
  518. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Init.clipboard.csv +0 -0
  519. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Init.csv +0 -0
  520. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Init.scr +0 -0
  521. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Maint.clipboard.bin +0 -0
  522. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Maint.clipboard.csv +0 -0
  523. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Maint.csv +0 -0
  524. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Maint.scr +0 -0
  525. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Manual.clipboard.bin +0 -0
  526. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Manual.clipboard.csv +0 -0
  527. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Manual.csv +0 -0
  528. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Manual.scr +0 -0
  529. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ModeChange.clipboard.bin +0 -0
  530. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ModeChange.clipboard.csv +0 -0
  531. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ModeChange.csv +0 -0
  532. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ModeChange.scr +0 -0
  533. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/PLCDateTime.clipboard.bin +0 -0
  534. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/PLCDateTime.clipboard.csv +0 -0
  535. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/PLCDateTime.csv +0 -0
  536. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/PLCDateTime.scr +0 -0
  537. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/PLCErrors.clipboard.bin +0 -0
  538. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/PLCErrors.clipboard.csv +0 -0
  539. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/PLCErrors.csv +0 -0
  540. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/PLCErrors.scr +0 -0
  541. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionBoilerplate.clipboard.bin +0 -0
  542. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionBoilerplate.clipboard.csv +0 -0
  543. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionBoilerplate.csv +0 -0
  544. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionBoilerplate.scr +0 -0
  545. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionErrors.clipboard.bin +0 -0
  546. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionErrors.clipboard.csv +0 -0
  547. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionErrors.csv +0 -0
  548. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionErrors.scr +0 -0
  549. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionExecuteSteps.clipboard.bin +0 -0
  550. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionExecuteSteps.clipboard.csv +0 -0
  551. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionExecuteSteps.csv +0 -0
  552. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionExecuteSteps.scr +0 -0
  553. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionHMI.clipboard.bin +0 -0
  554. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionHMI.clipboard.csv +0 -0
  555. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionHMI.csv +0 -0
  556. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionHMI.scr +0 -0
  557. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionStates.clipboard.bin +0 -0
  558. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionStates.clipboard.csv +0 -0
  559. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionStates.csv +0 -0
  560. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ProductionStates.scr +0 -0
  561. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ReadInputs.clipboard.bin +0 -0
  562. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ReadInputs.clipboard.csv +0 -0
  563. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ReadInputs.csv +0 -0
  564. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ReadInputs.scr +0 -0
  565. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/RecipeChange.clipboard.bin +0 -0
  566. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/RecipeChange.clipboard.csv +0 -0
  567. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/RecipeChange.csv +0 -0
  568. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/RecipeChange.scr +0 -0
  569. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Rotate.clipboard.bin +0 -0
  570. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Rotate.clipboard.csv +0 -0
  571. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Rotate.csv +0 -0
  572. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Rotate.scr +0 -0
  573. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/SFCExample.clipboard.bin +0 -0
  574. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/SFCExample.clipboard.csv +0 -0
  575. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/SFCExample.csv +0 -0
  576. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/SFCExample.scr +0 -0
  577. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/SetOutputs.clipboard.bin +0 -0
  578. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/SetOutputs.clipboard.csv +0 -0
  579. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/SetOutputs.csv +0 -0
  580. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/SetOutputs.scr +0 -0
  581. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/SetOutputsManual.clipboard.bin +0 -0
  582. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/SetOutputsManual.clipboard.csv +0 -0
  583. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/SetOutputsManual.csv +0 -0
  584. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/SetOutputsManual.scr +0 -0
  585. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ThermErrors.clipboard.bin +0 -0
  586. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ThermErrors.clipboard.csv +0 -0
  587. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ThermErrors.csv +0 -0
  588. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/ThermErrors.scr +0 -0
  589. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Validation.clipboard.bin +0 -0
  590. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Validation.clipboard.csv +0 -0
  591. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Validation.csv +0 -0
  592. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/Validation.scr +0 -0
  593. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/WarnTimestamp.clipboard.bin +0 -0
  594. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/WarnTimestamp.clipboard.csv +0 -0
  595. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/WarnTimestamp.csv +0 -0
  596. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/WarnTimestamp.scr +0 -0
  597. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_CopyOrJumpState.clipboard.bin +0 -0
  598. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_CopyOrJumpState.clipboard.csv +0 -0
  599. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_CopyOrJumpState.csv +0 -0
  600. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_CopyOrJumpState.scr +0 -0
  601. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_CtrlCmd2StateRequest.clipboard.bin +0 -0
  602. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_CtrlCmd2StateRequest.clipboard.csv +0 -0
  603. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_CtrlCmd2StateRequest.csv +0 -0
  604. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_CtrlCmd2StateRequest.scr +0 -0
  605. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_IsCmdValid.clipboard.bin +0 -0
  606. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_IsCmdValid.clipboard.csv +0 -0
  607. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_IsCmdValid.csv +0 -0
  608. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_IsCmdValid.scr +0 -0
  609. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_MapCmd2Val.clipboard.bin +0 -0
  610. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_MapCmd2Val.clipboard.csv +0 -0
  611. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_MapCmd2Val.csv +0 -0
  612. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_MapCmd2Val.scr +0 -0
  613. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_MapVal2State.clipboard.bin +0 -0
  614. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_MapVal2State.clipboard.csv +0 -0
  615. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_MapVal2State.csv +0 -0
  616. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_MapVal2State.scr +0 -0
  617. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_StateComplete2Request.clipboard.bin +0 -0
  618. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_StateComplete2Request.clipboard.csv +0 -0
  619. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_StateComplete2Request.csv +0 -0
  620. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/fixtures/tumbler/subroutines/sm_StateComplete2Request.scr +0 -0
  621. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/golden_io.py +0 -0
  622. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_counter.py +0 -0
  623. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_decode.py +0 -0
  624. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_decode_multi.py +0 -0
  625. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_decode_program_tumbler.py +0 -0
  626. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_decode_rtf_oracle.py +0 -0
  627. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_empty_multirow.py +0 -0
  628. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_encode.py +0 -0
  629. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_encode_multi.py +0 -0
  630. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_model.py +0 -0
  631. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_shift.py +0 -0
  632. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/ladder/test_verify_status.py +0 -0
  633. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/test_coverage.py +0 -0
  634. {laddercodec-0.2.2 → laddercodec-0.3.0}/tests/test_smoke.py +0 -0
  635. {laddercodec-0.2.2 → laddercodec-0.3.0}/uv.lock +0 -0
@@ -43,6 +43,7 @@ src/laddercodec/
43
43
  ├── binary_helpers.py # Shared binary primitives: UTF-16LE encode/decode, tagged fields
44
44
  ├── decode.py # Decoder: decode() + internal decode_rung(), decode_rungs()
45
45
  ├── decode_program.py # Program file decoder: decode_program() — Scr*.tmp to Program
46
+ ├── compat.py # find_v4_only() / is_v4_only(): instructions an older CLICK would mangle
46
47
  ├── cell.py # Cell object builders: ClickCell, preamble, terminal, row
47
48
  ├── topology.py # Program header, rung preamble, cell offset math, wire flags
48
49
  ├── empty_multirow.py # Deterministic empty multi-row payload synthesis
@@ -52,6 +53,7 @@ src/laddercodec/
52
53
  │ ├── contact.py # Contact (NO/NC/edge/immediate), build_blob(), cell_params(), parser
53
54
  │ ├── comparison.py # CompareContact (==, !=, >, <, >=, <=), build_blob(), cell_params(), parser
54
55
  │ ├── coil.py # Coil (out/latch/reset, range, immediate, oneshot), build_blob(), cell_params(), parser
56
+ │ ├── out_variant.py # OutVariant (CLICK v4 toggle/debounce/flasher/timed), build_blob(), cell_params(), parser
55
57
  │ ├── timer.py # Timer (on_delay/off_delay, retentive), build_blob(), cell_params(), parser
56
58
  │ ├── copy.py # Copy (single/block/fill), BlockCopy, Fill — build_blob(), cell_params(), parser
57
59
  │ └── raw.py # RawInstruction (opaque blob passthrough), build_blob(), cell_params()
@@ -91,6 +93,7 @@ src/laddercodec/
91
93
  tests/
92
94
  ├── test_smoke.py # Basic sanity check
93
95
  ├── test_coverage.py # Coverage golden fixture tests (instruction variants)
96
+ ├── test_v4_captures.py # CLICK v4 captures: each rung decodes to its comment; native blob matching
94
97
  ├── golden_io.py # Golden CSV/BIN read/write helpers
95
98
  ├── ladder/
96
99
  │ ├── test_encode.py # encode() pipeline, multi-row, comments, wires, NOP
@@ -112,7 +115,8 @@ tests/
112
115
  └── fixtures/
113
116
  ├── ladder_captures/golden/ # Golden CSV/BIN fixtures
114
117
  ├── scr_captures/ # Scr program files + clipboard bins (decode_program)
115
- └── tumbler/ # 34 real programs: <name>.scr + <name>.clipboard.{bin,csv}
118
+ ├── tumbler/ # 34 real programs: <name>.scr + <name>.clipboard.{bin,csv}
119
+ └── v4_captures/ # CLICK v4 copy-backs of pyrung capture stubs (math, out, drum)
116
120
  ```
117
121
 
118
122
  Ladder golden fixtures are verified through Click paste round-trip. In `scr_captures`, `time_drums.bin` is synthetic (see that directory's README); do not use its differences from SCR as evidence of native cleanup. 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.
@@ -209,8 +213,10 @@ When the user provides a `.bin` + `.csv` from a Click capture:
209
213
 
210
214
  1. **Inspect the capture:** `uv run devtools/inspect_bin.py <file.bin>` — shows known instructions with `to_csv()` output, and RawInstruction/Unknown blobs with full tagged-field breakdown (tag IDs, sentinel types, values).
211
215
  2. **Identify what's new:** RawInstruction means the class name is recognized but the func code isn't. The field breakdown shows exactly which func code / field values differ from existing support.
212
- 3. **Update the code:** add func codes, fields, or new instruction modules as needed. Update `csv/converter.py` to pass new kwargs through.
216
+ 3. **Update the code:** add func codes, fields, or new instruction modules as needed; CSV parsing goes through the family `SPEC`'s `parse_csv_call`.
213
217
  4. **Update coverage CSV:** `tests/fixtures/coverage/golden/<name>.csv` — use kwargs style for boolean flags (e.g. `oneshot=1`).
214
218
  5. **Verify:** `make test` + `make lint`.
215
219
 
220
+ For CLICK v4 instructions captured from pyrung stubs (`tests/fixtures/v4_captures/`, `tests/test_v4_captures.py`), see "Capturing from CLICK v4" in the guide.
221
+
216
222
  See [`docs/guides/adding-instructions.md`](docs/guides/adding-instructions.md) for the full guide.
@@ -8,6 +8,30 @@
8
8
  Review and condense before release — entries accumulate during development and
9
9
  should be edited into shape before moving from Unreleased to a version heading. -->
10
10
 
11
+ ## 0.3.0 (2026-11-01)
12
+
13
+ ### Added
14
+ - **CLICK v4 Out variants**: `toggle(C1)`, `debounce(...)`, `flasher(...)` and `timed(...)` decode and encode as `OutVariant`, exported from the root package, matching Click-written blobs byte for byte.
15
+ - **CLICK v4 Time & Event drum**: `time_event_drum(outputs=[...],presets=[1000,None,DS1],events=[None,C1,C2],unit=Tms,...)` decodes and encodes as `Drum(drum_kind="time_event")`, with `None` marking a step without a preset or event.
16
+ - **CLICK v4 Break and Continue**: `break()` and `continue()` decode and encode as `Break` and `Continue`, exported from the root package; both used to decode as `next()`.
17
+ - **CLICK v4 Math**: wide ranges encode up to CLICK's limit of 5000 interior addresses, where more than 500 used to raise `ValueError`, and `XD`/`YD` registers are recognized as operands, including `XD0u` and its place inside a range.
18
+ - **CLICK v4 check**: `find_v4_only(rungs)` lists the instructions an older CLICK would silently change or may not hold (Break/Continue, Out variants, Time & Event drums, time drums with a duration from a register, v4 math functions, SUM over bits, Math ranges past 500 interior addresses), and `is_v4_only()` checks one.
19
+ - **Pin OR legs**: OR legs under a counter, shift or drum pin push the later pins down and grow the box as CLICK does, in clipboard and SCR, exposed as `pin_rows`.
20
+
21
+ ### Changed
22
+ - **CSV read**: a blank-AF row directly under `count_down` is an OR leg of its Down input rather than the bridge row.
23
+ - **CSV errors**: pins out of order or repeated raise `ConvertError` instead of being dropped, a pin a timer does not have (e.g. `.down()`) raises `ConvertError` instead of reading as a blank row, and `write_csv` refuses a leg drawn onto an unused pin's row, which CSV cannot express.
24
+
25
+ ### Fixed
26
+ - **Math encode**: formulas and constants are written the way Click's editor writes them (`ABS(x)*2` → `ABS ( x ) * 2`, `RAND` in its infix form, range interiors listed, `Ah` → `UH10`, `-5` → `H-5`, `-2.5` → `F-2.5`), so pasted formulas no longer raise Math instruction errors or fail CLICK v4's syntax check.
27
+ - **Math encode**: `show_nicknames=True` wraps each operand once, where repeated or overlapping addresses (`DS10 + DS1 + DS1`) came out corrupted.
28
+ - **Math decode**: `XD`/`YD` formulas keep their display constants, instead of `XD0 AND 1h` reading back as `XD0 AND UH1`.
29
+ - **Drum encode**: with Jump off, Jog takes the func code Jump would have, so CLICK v4 no longer rejects a pasted drum with C000A ("all inputs of the box instruction must originate from the same branch").
30
+ - **Unknown coils and drums**: an Out coil with an unknown func code or a drum with an unknown base decodes as `raw(...)`, instead of silently decoding as a plain `out(...)` or `time_drum`.
31
+ - **Raw multi-part instructions**: a `raw(...)` token with part count 2+ rebuilds Click's part bytes, so `write_csv` no longer fails its round-trip check on raw drums and SCR raw blobs carry the right bytes.
32
+ - **CSV read, OR inputs on boxes**: OR legs under any timer, counter, shift or drum input push its later pins down, so a `count_down` fed by a 3+ row OR no longer raises and a retentive timer fed by a 2+ row OR keeps its `.reset()`.
33
+ - **CSV writer**: a box's empty pin rows and a `count_down`'s empty top row stay in place when a blank-AF row or a `count_down` follows, where `write_csv` used to fail its round-trip check.
34
+
11
35
  ## 0.2.2 (2026-09-10)
12
36
 
13
37
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: laddercodec
3
- Version: 0.2.2
3
+ Version: 0.3.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://pyrung.com/laddercodec/
@@ -31,7 +31,8 @@ def main() -> None:
31
31
  row = data[cursor]
32
32
  col = data[cursor + 1]
33
33
  blob_start = cursor + 8
34
- cls, typ, end_off, m1 = blob
34
+ cls, typ, end_off, part_rows = blob
35
+ m1 = len(part_rows)
35
36
  next_pos = end_off + 2 + data[end_off] # trailer-aware advance
36
37
 
37
38
  # Parse tagged fields
@@ -26,7 +26,16 @@ PAGES: tuple[ReferencePage, ...] = (
26
26
  title="Codec API",
27
27
  tier="Stable Core",
28
28
  summary="Encode and decode Click clipboard binary and program files.",
29
- symbols=("encode", "decode", "decode_program", "Rung", "Program", "Project"),
29
+ symbols=(
30
+ "encode",
31
+ "decode",
32
+ "decode_program",
33
+ "Rung",
34
+ "Program",
35
+ "Project",
36
+ "find_v4_only",
37
+ "is_v4_only",
38
+ ),
30
39
  ),
31
40
  ReferencePage(
32
41
  slug="csv",
@@ -44,6 +53,7 @@ PAGES: tuple[ReferencePage, ...] = (
44
53
  "Contact",
45
54
  "CompareContact",
46
55
  "Coil",
56
+ "OutVariant",
47
57
  "Timer",
48
58
  "Counter",
49
59
  "Copy",
@@ -60,6 +70,8 @@ PAGES: tuple[ReferencePage, ...] = (
60
70
  "End",
61
71
  "ForLoop",
62
72
  "Next",
73
+ "Break",
74
+ "Continue",
63
75
  "Send",
64
76
  "Receive",
65
77
  "ModbusAddress",
@@ -69,7 +69,14 @@ In `src/laddercodec/instructions/<module>.py`:
69
69
  - Add any new fields to the dataclass (e.g. `oneshot: bool = False`)
70
70
  - Update `build_blob()` to emit the new field value
71
71
  - Update `to_csv()` to include the new parameter
72
- - Update `parse_blob()` to extract the new field from the func code table
72
+ - Update `from_tags()` to extract the new field from the func code table
73
+
74
+ If the new variant shares a class name with an existing family (CLICK v4's toggle,
75
+ debounce, flasher and timed are all class `Out`, type 0x2715), the existing family's
76
+ `from_tags()` must return `None` for func codes it doesn't know. Otherwise the variant
77
+ decodes silently as the old instruction. `from_tags()` dispatch tries every family in
78
+ turn, so the new family can set `binary_class_names=()` and leave the class name's
79
+ registry entry to the existing one (see `out_variant.py`).
73
80
 
74
81
  ### 3. Update the CSV-facing parse path
75
82
 
@@ -101,7 +108,7 @@ Same as above. For new types, inspect will often show `RawInstruction` with a ne
101
108
  In `src/laddercodec/instructions/`:
102
109
 
103
110
  - New `@dataclass` inheriting from `AfInstruction` (or `ConditionInstruction`)
104
- - Implement `to_csv()`, `build_blob()`, `cell_params()`, and `parse_blob()`
111
+ - Implement `to_csv()`, `build_blob()`, `cell_params()`, and a module-level `from_tags()`
105
112
  - Follow existing modules (coil.py, timer.py, copy.py) as templates
106
113
  - Add `InstructionType` enum value in `model.py` if it uses a new type marker
107
114
 
@@ -114,11 +121,19 @@ If the instruction also needs auto-padding in CSV, set `min_csv_rows=N` on the f
114
121
 
115
122
  Example: timers currently use `visual_rows=2` and `min_csv_rows=2`, while counter/shift/drum families use explicit higher CSV row counts because their lower rows have pin semantics.
116
123
 
124
+ `visual_rows` sets both cell header bytes, `+0x09` (rows spanned) and `+0x0A`
125
+ (sub-rows). When a native capture shows them differing, add `"sub_rows"` for
126
+ `+0x0A`: CLICK v4's timed coil spans 2 rows but writes 3 (`{"visual_rows": 2, "sub_rows": 3}`).
127
+
128
+ **Reading tags in `from_tags()`:** flag tags (`0x11xx`/`0x12xx`) are present in
129
+ `tags` with an empty value when set, and absent when `0`. Test them with
130
+ `0x1201 in tags`, not by value.
131
+
117
132
  Also add a family `SPEC` in the module:
118
133
 
119
134
  - `binary_class_names`
120
135
  - `csv_names`
121
- - `parse_blob`
136
+ - `from_tags`
122
137
  - `parse_csv_call` (for AF families)
123
138
  - `pin_names` if the family uses dot-prefixed continuation rows
124
139
  - `min_csv_rows` if the family should auto-pad in CSV
@@ -129,6 +144,8 @@ Also add a family `SPEC` in the module:
129
144
  |------|---------------|
130
145
  | `instructions/__init__.py` | Register the family `SPEC` in `AF_FAMILY_SPECS` or `CONDITION_FAMILY_SPECS`, and re-export the new class |
131
146
  | `__init__.py` | Re-export the new class in the public API |
147
+ | `tests/test_public_api.py` | Add the class to `EXPECTED_ROOT_EXPORTS`, which pins the root `__all__` |
148
+ | `docs/gen_reference.py` | Add the class to the Instructions API page; `make docs-build` fails on an unlisted export |
132
149
 
133
150
  `KNOWN_AF_NAMES` is now derived from the registered family specs, so `csv/ast.py` does not need manual token updates.
134
151
 
@@ -162,7 +179,7 @@ Coverage golden fixtures live in `tests/fixtures/coverage/golden/`. Each fixture
162
179
 
163
180
  ### Adding a fixture
164
181
 
165
- 1. Create `tests/fixtures/coverage/golden/<rung_id>.csv` by hand — one rung per file, 33-column canonical format.
182
+ 1. Create `tests/fixtures/coverage/golden/<rung_id>.csv` by hand in the 33-column canonical format. Usually one rung per file; a file can hold several rungs (`math__v4.csv` holds 23) and is verified as one paste.
166
183
  2. Run `make coverage-golden` to generate the `.bin` from the CSV.
167
184
  3. Paste-verify in Click using `clicknick-rung guided`.
168
185
  4. `make test` — each `.csv` with a matching `.bin` gets a parametrized test comparing encoded output to golden binaries.
@@ -187,6 +204,49 @@ uv run devtools/combine_coverage.py --seed 42 # reproducible pick
187
204
 
188
205
  This picks N random coverage CSVs, stacks their data rows into one multi-row rung, and writes `devtools/combined.csv` + `devtools/combined.bin` for paste-testing.
189
206
 
207
+ ## Capturing from CLICK v4
208
+
209
+ New CLICK v4 instructions are captured in groups. The paste CSVs are built with
210
+ pyrung by `scratchpad/click-v4/captures/v4_capture.py`, whose README has the
211
+ CLICK-side steps and address map per group. Each rung's comment is its id, then
212
+ every AF token it should decode to, in row order:
213
+
214
+ ```
215
+ #,drum__te_ds
216
+ #,"time_event_drum(outputs=[C1321,C1322],presets=[DS1301,None],...)"
217
+ #,.reset()
218
+ ```
219
+
220
+ Run clicknick against the local checkouts, so `load` encodes with the laddercodec
221
+ you are changing. From the clicknick directory:
222
+
223
+ ```bash
224
+ make install-dev # editable ../pyclickplc, ../pyrung, ../laddercodec
225
+ UV_NO_SYNC=1 uv run --no-sync clicknick-rung load ../laddercodec/scratchpad/click-v4/captures/stubs/<group>.csv
226
+ # build each rung in CLICK as its comment says, copy them all back, then:
227
+ UV_NO_SYNC=1 uv run --no-sync clicknick-rung save ../laddercodec/scratchpad/click-v4/captures/copyback/<group>
228
+ ```
229
+
230
+ A rung whose instruction laddercodec can't encode yet is pasted as a placeholder
231
+ (NOP, or a v3 instruction with `1` standing in for a blank or register preset);
232
+ its comment still names the target.
233
+
234
+ In laddercodec:
235
+
236
+ 1. Copy `scratchpad/click-v4/captures/copyback/<group>.bin` to `tests/fixtures/v4_captures/`. `tests/test_v4_captures.py`
237
+ checks every labelled rung: one still decoding as `raw(...)` is xfail, any other
238
+ mismatch fails, and every capture must survive `write_csv`.
239
+ 2. Map the fields of the raw blobs (`devtools/inspect_bin.py`, or the `raw(...)`
240
+ tokens in the saved CSV) and model the instruction until its rungs pass.
241
+ 3. Add a test that re-encoding matches the blobs Click wrote, field for field
242
+ (see `test_out_variant_blobs_match_native` and `test_time_event_drum_blobs_match_native`).
243
+ 4. For the encode side, copy `scratchpad/click-v4/captures/expected/<group>.csv` (real tokens in the
244
+ AF column) to a coverage golden `<family>__v4.csv`, run `make coverage-golden`,
245
+ and paste-verify it with `clicknick-rung guided`.
246
+
247
+ A typo made while building rungs in CLICK shows up as a failing rung, not an
248
+ xfail. Fix the rung in CLICK and save again.
249
+
190
250
  ## Clicknick compatibility
191
251
 
192
252
  The `clicknick-rung guided` tool extracts operand addresses from CSV tokens for MDB provisioning. It uses `to_csv()` + regex to find address patterns, so **new instruction types work automatically** — no clicknick changes needed.
@@ -293,6 +293,38 @@ Builder side conditions are emitted as continuation rows with dot tokens in `AF`
293
293
  Pin rows are independent left-rail paths, not AND-chained through the parent
294
294
  output row conditions.
295
295
 
296
+ Pins go in a fixed order (timers: reset; `count_up`: down, reset; `count_down`:
297
+ reset; `shift`: clock, reset; drums: reset, jump, jog). Rows without an AF token
298
+ between the instruction and a pin, or between two pins, are OR legs of the input
299
+ above, and they push the later pins down. CLICK grows the box to match:
300
+
301
+ ```csv
302
+ R,C1,-,...,-,"time_drum(...)"
303
+ ,C2,T,-,...,-,.reset()
304
+ ,C3,,...,,
305
+ ,C4,-,...,-,.jump(DS2)
306
+ ```
307
+
308
+ Here `.jump()` is on row 3, not row 2. An unused pin still takes a row of its
309
+ own, below the legs of the pin above it: with Jump off, `.reset()` with one leg
310
+ then `.jog()` puts Jog on row 4, with a blank Jump row 3 (CLICK lays out a leg
311
+ added with Insert Row the same way). Blank rows just above the next pin are read
312
+ as the unused pins' rows, not legs. Legs under the last pin sit below the box.
313
+
314
+ The same holds for legs under the main input:
315
+
316
+ ```csv
317
+ R,X1,T:X2,T,-,...,-,"count_down(CT1,CTD1,preset=3)"
318
+ ,,T:X3,|,,...,,
319
+ ,,X4,,,...,,
320
+ ,X9,-,...,-,.reset()
321
+ ```
322
+
323
+ `count_down`'s main input is its Down input, on box row 1 under the unused Up,
324
+ so this box is 5 rows with Reset on row 4. A `count_up` without `.down()` puts
325
+ the unused Down row under the main input's legs. A timer without `.reset()`
326
+ stays 2 rows, with its main input's legs beside and below it.
327
+
296
328
  ## Parsing conveniences
297
329
 
298
330
  `laddercodec.read_csv()` accepts a few parsing conveniences beyond the canonical
@@ -308,7 +340,9 @@ writer contract:
308
340
  `forloop(count, oneshot=...)` lowers to:
309
341
 
310
342
  1. `for(count)` or `for(count,oneshot=1)` row (`marker=R`)
311
- 2. Body instruction rows (`marker=R` per emitted body instruction row)
343
+ 2. Body rungs (`marker=R` each): a bare body instruction is a wire-only rung; a
344
+ body rung with contacts keeps them, and holds `break()` / `continue()`
345
+ (CLICK v4). A nested loop is its own `for` .. `next()` run, up to three deep.
312
346
  3. Closing `next()` row (`marker=R`)
313
347
 
314
348
  ## Subroutine tail guarantee
@@ -383,6 +417,7 @@ Producer may emit:
383
417
  - `return()`
384
418
  - `for(count)` or `for(count,oneshot=1)`
385
419
  - `next()`
420
+ - `break()`, `continue()` (CLICK v4) - on a contacted rung inside a loop
386
421
  - `raw(ClassName,hex)` - opaque instruction passthrough for binary round-trip
387
422
  fidelity. `ClassName` is the Click binary class name (unquoted) and `hex` is
388
423
  the raw blob as a hex string. Runtime no-op; preserved so CSV -> DSL -> CSV
@@ -29,14 +29,15 @@ All standard Click instruction types are decoded into domain objects:
29
29
  - **Contacts** → `Contact` (NO, NC, edge, immediate)
30
30
  - **Comparison contacts** → `CompareContact` (==, !=, >, <, >=, <=)
31
31
  - **Coils** → `Coil` (out, latch, reset, immediate, range, oneshot)
32
+ - **CLICK v4 Out variants** → `OutVariant` (toggle, debounce, flasher, timed)
32
33
  - **Timers** → `Timer` (on_delay, off_delay, retentive)
33
34
  - **Counters** → `Counter` (count_up, count_down)
34
35
  - **Copy family** → `Copy`, `BlockCopy`, `Fill`, `Pack`, `Unpack`
35
36
  - **Math** → `Math` (decimal/hex expressions)
36
37
  - **Shift registers** → `Shift`
37
- - **Drum sequencers** → `Drum` (event/time)
38
+ - **Drum sequencers** → `Drum` (event, time, and CLICK v4 time & event)
38
39
  - **Table search** → `Search`
39
- - **Flow control** → `Call`, `Return`, `End`, `ForLoop`, `Next`
40
+ - **Flow control** → `Call`, `Return`, `End`, `ForLoop`, `Next`, `Break`, `Continue` (CLICK v4)
40
41
  - **Modbus** → `Send`, `Receive`
41
42
 
42
43
  Unrecognised cells fall back to `RawInstruction` with the raw bytes preserved. This keeps the decoder forward-compatible — unknown instruction types don't crash the pipeline.
@@ -109,6 +110,24 @@ The returned `Program` dataclass has:
109
110
 
110
111
  Each `Rung` in `program.rungs` has the same structure as clipboard-decoded rungs, so you can pass them to `encode()`, `write_csv()`, or any other API that accepts `Rung` objects.
111
112
 
113
+ ## Check for CLICK v4 instructions
114
+
115
+ An older CLICK pastes v4 rungs without complaint and changes them: Break and
116
+ Continue come back as plain Next, which closes the loop early. Check before
117
+ pasting into a pre-v4 CLICK:
118
+
119
+ ```python
120
+ from laddercodec import find_v4_only
121
+
122
+ for index, instruction in find_v4_only(rungs):
123
+ print(f"rung {index}: {instruction.to_csv()} needs CLICK v4")
124
+ ```
125
+
126
+ v4-only: `Break`, `Continue`, `OutVariant`, a time & event `Drum`, a time `Drum`
127
+ with a duration from a register, and `Math` using MAX, MIN, MDN, AVG, ABS, RAND,
128
+ SUM over a bit range, or ranges past 500 interior addresses. `is_v4_only()` checks
129
+ a single instruction.
130
+
112
131
  ## Round-trip identity
113
132
 
114
133
  For all supported instruction types:
@@ -189,7 +189,7 @@ raw address for that operand.
189
189
  All standard Click instruction families are supported from the root package:
190
190
 
191
191
  - Condition side: `Contact`, `CompareContact`
192
- - AF side: `Coil`, `Timer`, `Counter`, `Copy`, `BlockCopy`, `Fill`, `Pack`, `Unpack`, `Math`, `Shift`, `Search`, `Drum`, `Call`, `Return`, `End`, `ForLoop`, `Next`, `Send`, `Receive`
192
+ - AF side: `Coil`, `OutVariant`, `Timer`, `Counter`, `Copy`, `BlockCopy`, `Fill`, `Pack`, `Unpack`, `Math`, `Shift`, `Search`, `Drum`, `Call`, `Return`, `End`, `ForLoop`, `Next`, `Send`, `Receive`
193
193
 
194
194
  Unknown AF blobs can still be preserved via `RawInstruction`, which keeps the
195
195
  binary payload intact for lossless round-trip.
@@ -0,0 +1,206 @@
1
+ # Instruction Blobs
2
+
3
+ This page documents the variable-length instruction data that follows the cell header in instruction cells. The blob starts at cell offset +0x25.
4
+
5
+ For field layouts, func code tables, and tag constants for each known instruction type, see the source in `src/laddercodec/instructions/` — each module (`contact.py`, `comparison.py`, `coil.py`, `timer.py`) is the authoritative reference.
6
+
7
+ ## Generic blob structure
8
+
9
+ All instruction blobs follow the same pattern:
10
+
11
+ ```
12
+ [UTF-16LE class name, null-terminated]
13
+ [type marker: uint32 LE, high byte always 0x27]
14
+ [part count: uint16 LE (0x01 for contacts/coils, 0x02 for timers)]
15
+ [extra bytes: (part_count - 1) bytes, if part_count > 1 — each later part's row]
16
+ [field count: uint32 LE]
17
+ [tagged fields...]
18
+ ```
19
+
20
+ ### Part rows
21
+
22
+ A tall instruction's extra bytes give the row, below the main row, of each later
23
+ part: `01` for a timer's reset, `01 02` for a counter (down, reset) or shift
24
+ (clock, reset), `01 02 03` for a drum (reset, jump, jog). OR legs under an
25
+ input (the main one included) push the later parts down, and CLICK grows the
26
+ box: a drum with one leg under reset is `01 03 04`. A count_down's main part is
27
+ its unused Up input, so its Down input is the first extra byte. The AF cell's `+0x09` becomes the last part's row + 1;
28
+ `+0x0A` keeps the base height (`tests/fixtures/v4_captures/pins.bin`).
29
+
30
+ ### Tagged fields
31
+
32
+ Each field is:
33
+
34
+ ```
35
+ [2-byte tag]
36
+ [FF FF FF FF sentinel]
37
+ [UTF-16LE null-terminated value]
38
+ ```
39
+
40
+ Field values are string-encoded even for numeric data (e.g. `"1000"` for a timer preset). Timer fields 6–7 use a variant format with a 4-byte sub-marker instead of the `FF FF FF FF` sentinel.
41
+
42
+ ## Known binary class names
43
+
44
+ | Class name | Type markers | Instruction | Source |
45
+ |---|---|---|---|
46
+ | `ContactNO` | 0x2711 (NO), 0x2712 (NC) | NO/NC contacts | `contact.py` |
47
+ | `Edge` | 0x2713 | Rising/falling edge contacts | `contact.py` |
48
+ | `Compare` | 0x2714 | Comparison contacts (==, !=, >, <, >=, <=) | `comparison.py` |
49
+ | `Out` | 0x2715, 0x2716, 0x2717 | All coil types (out, latch, reset) | `coil.py` |
50
+ | `Tmr` | 0x2718 | Timers (on_delay, off_delay) | `timer.py` |
51
+
52
+ The encoder uses `Out` as the class name for all coil types; the type marker and func code determine the variant. The decoder also recognizes `Latch` and `Reset` class names from native Click captures.
53
+
54
+ ## Out variants (CLICK v4)
55
+
56
+ CLICK v4's toggle, debounce, flasher and timed coils are `Out` blobs with type
57
+ marker 0x2715, the same as a plain `out`. They carry 15 fields, and only the
58
+ func code separates them from plain coils. An `Out` blob whose func code is in
59
+ neither table decodes as `raw(Out,...)`. Source: `out_variant.py`.
60
+
61
+ | Tag | Field |
62
+ |---|---|
63
+ | `0x6066` | target |
64
+ | `0x6067` | range end (always empty) |
65
+ | `0x60B3` / `0x60B4` | on preset / on accumulator (`TD`) |
66
+ | `0x60B5` / `0x60B6` | off preset / off accumulator (debounce, flasher) |
67
+ | `0x11F8` | oneshot (always `0`) |
68
+ | `0x11F5` | immediate (toggle) |
69
+ | `0x1246` | `1` for toggle |
70
+ | `0x1247` | maintained (timed) |
71
+ | `0x21F9` | time unit: 0 ms, 1 s, 2 min |
72
+ | `0x2248` | variant: 0 toggle, 1 debounce, 2 flasher, 3 timed |
73
+ | `0x3218` | func code |
74
+ | `0x20CA` | always `2` |
75
+
76
+ | Variant | Func codes | Units | Rows (`+0x09` / `+0x0A`) |
77
+ |---|---|---|---|
78
+ | toggle | 8224, immediate 8225 | — | 1 / 1 |
79
+ | debounce | 8226 ms, 8227 s | ms, s | 3 / 3 |
80
+ | flasher | 8228 ms, 8229 s | ms, s | 3 / 3 |
81
+ | timed | 8230–8232 ms/s/min, maintained 8233–8235 | ms, s, min | 2 / 3 |
82
+
83
+ Each phase stores only its accumulator; Click claims the `T` of the same number
84
+ with it. Timed is the one AF instruction whose cell header has more visual
85
+ sub-rows (`+0x0A`) than rows spanned (`+0x09`).
86
+
87
+ ## Time & Event drum (CLICK v4)
88
+
89
+ A drum's base is tag `0x2200`: `0` time, `1` event, `2` time & event. Any other
90
+ value decodes as `raw(Drum,...)`. Source: `drum.py`.
91
+
92
+ CLICK v4 copies every drum back with 82 fields: the 63 v3 fields, then 16 preset
93
+ slots (`0x6891`), `0x428A`, `0x6068` and the terminator. The encoder writes the
94
+ 82-field layout for time & event drums only. Time and event drums keep the
95
+ 64-field v3 layout, which CLICK v4 still accepts.
96
+
97
+ | Tag | Time & event drum |
98
+ |---|---|
99
+ | `0x6872` ×16 | events (blank for a step without one) |
100
+ | `0x6891` ×16 | presets (blank for a step without one) |
101
+ | `0x6068` | done bit of the accumulator's timer (`TD101` → `T101`) |
102
+ | `0x428A` | `-1` as written by the encoder; see below |
103
+ | `0x3A05` ×4 | func codes; no-jog base Tms 10503, Ts 10510, Tm 10517, Th 10524, Td 10532 |
104
+
105
+ The func codes have the same 7-code block shape as the time drum (base, reset,
106
+ jump, then jog group +3..+6) and the same Td skip.
107
+
108
+ In every drum the codes run consecutively over the enabled pins. With Jump off,
109
+ Jog takes Jump's code: event `8494, 8495, 0, 8496`, not `8497`. CLICK v3
110
+ accepts the skipped code. CLICK v4 pastes it, then fails the syntax check with
111
+ C000A ("All inputs of the box instruction must originate from the same branch")
112
+ until the drum is reopened and OK'd (`v4_captures/drum_jog.bin`).
113
+
114
+ `0x428A` looks like leftover editor state. Click fills in `-1` for a pasted drum
115
+ that lacks the field. A time drum switched to Time & Event and back came out
116
+ `-4`, with new func codes (Tms 10247/10248 where the v3 table has 8455/8456).
117
+
118
+ ## Break and Continue (CLICK v4)
119
+
120
+ Break and Continue are class `Next` (type 0x2726), told apart by the func code in
121
+ tag `0x3218`. Source: `forloop.py`.
122
+
123
+ | `0x3218` | Instruction |
124
+ |---|---|
125
+ | absent | `next()`: v3 writes Next with the terminator field only |
126
+ | `9220` | `next()`: CLICK v4 writes the func code |
127
+ | `9232` | `continue()` |
128
+ | `9233` | `break()` |
129
+
130
+ Any other func code decodes as `raw(Next,...)`. Break and Continue are encoded
131
+ with the two fields Click writes; `next()` keeps the one-field v3 form. Each
132
+ version accepts either Next on paste and copies back its own: v3 drops `9220`,
133
+ v4 adds it.
134
+
135
+ ## Math formulas
136
+
137
+ A Math blob (class `Math`, type 0x271A) has 1010 tagged fields: 9 header
138
+ fields, 500 operand slots (tag `0x6888`), 500 reserved slots (tag `0x688C`) and
139
+ a terminator. Source: `math.py`.
140
+
141
+ The formula appears four times in the header:
142
+
143
+ | Tag | Field | Example for `SUM ( DS1 : DS3 ) + 5` |
144
+ |---|---|---|
145
+ | `0x61FF` | template, display | `SUM ( @ : @ ) + 5` |
146
+ | `0x6228` | formula, display | `SUM ( DS1 : DS3 ) + 5` |
147
+ | `0x6229` | template, internal | `SUM#(#@#:#@#)#+#H5` |
148
+ | `0x61FD` | formula, internal | `SUM#(#DS1#:#DS3#)#+#H5` |
149
+
150
+ - **Display form** is spaced the way Click's formula editor spaces it: one space
151
+ on each side of every operator, paren, comma and range colon (`ABS ( x )`,
152
+ `RAND ( 1 , 100 )`). The encoder normalizes `ABS(x)*2` to this form. A sign
153
+ stays on its constant (`( -5 )`) and is spaced from an address (`- DS401`).
154
+ - **Internal form** is the display form with spaces replaced by `#` and each
155
+ bare decimal literal prefixed with `H`. Click splits it on `#`, so an
156
+ unspaced `ABS(` becomes a single unknown token. In CLICK v4 that pastes but
157
+ raises a Math instruction error.
158
+ - **RAND** is stored infix in the internal form: `RAND ( a , b )` becomes
159
+ `a#RAND#b`, followed by a trailing `#` when RAND ends the formula
160
+ (`H1#RAND#H100#`, `H1#RAND#H10#+#DS1`). The display form keeps the function
161
+ call.
162
+
163
+ ### Operand and reserved slots
164
+
165
+ Each slot is `[2B tag][4B index LE][UTF-16LE value]`, and an empty slot is just
166
+ a null terminator. Operand slots hold every address in the formula, in order,
167
+ duplicates included. Reserved slots hold the interior addresses of each
168
+ `A : B` range, ranges in order. The endpoints are ordinary operands, so
169
+ `SUM ( DS201 : DS300 )` stores DS201 and DS300 as operands and DS202..DS299 in
170
+ the reserved slots.
171
+
172
+ An `XD` or `YD` range also lists the upper half of address 0:
173
+ `MAX ( XD0 : XD3 )` stores XD0u, XD1 and XD2.
174
+
175
+ CLICK v4 copies Math back with 5000 reserved slots, not 500, for 5510 fields.
176
+ A 500-slot blob still pastes into both v3 and v4, so the encoder writes 500
177
+ unless the ranges have more than 500 interiors. CLICK's editor stops listing
178
+ at 5000 without an error, even though the formula keeps the full range, and the
179
+ encoder does the same.
180
+
181
+ ## Math nickname flag
182
+
183
+ Math blobs contain a `nickname_flag` field (tag `0x2224`). When set to `"1"`,
184
+ Click displays project-level tag names instead of raw addresses in the math
185
+ formula. The flag is purely a display hint — the expression itself always
186
+ stores concrete addresses.
187
+
188
+ The `encode()` API exposes this via `show_nicknames=True`, which sets the flag
189
+ on all math instructions in the buffer.
190
+
191
+ ## Blob boundary detection
192
+
193
+ For unknown instruction types, the blob boundary can be detected using the generic multi-part formula:
194
+
195
+ 1. Read the class name (UTF-16LE, null-terminated)
196
+ 2. Read the type marker (uint32 LE)
197
+ 3. Read part count (uint16 LE), skip `(part_count - 1)` extra bytes
198
+ 4. Read field count (uint32 LE)
199
+ 5. Walk through tagged fields (each: 2B tag + 4B sentinel/marker + UTF-16LE value)
200
+ 6. The blob ends after all fields are consumed
201
+
202
+ The `RawInstruction` fallback uses this formula to capture the complete blob as opaque bytes, enabling round-trip for unsupported instruction types via `raw(ClassName,hex)` CSV tokens.
203
+
204
+ At the moment, `Email`, `Home`, `Position`, and `Velocity` still deliberately
205
+ travel through this raw path. They round-trip correctly, but they are not yet
206
+ modeled as dedicated DSL instruction classes.
@@ -0,0 +1,2 @@
1
+ copyback/*
2
+ !copyback/.gitkeep
@@ -0,0 +1,61 @@
1
+ # CLICK v4 captures
2
+
3
+ `v4_capture.py` writes one paste CSV per group into `stubs/`, plus pyrung's own export into `expected/`.
4
+ Each rung's comment is its id, then every AF token it should decode to. laddercodec's
5
+ `tests/test_v4_captures.py` checks every captured rung against that comment.
6
+ The laddercodec side of the loop is in `docs/guides/adding-instructions.md`, "Capturing from CLICK v4".
7
+
8
+ The generator builds the rungs with pyrung, so it runs in pyrung's environment. From the laddercodec root:
9
+
10
+ ```
11
+ uv run --project ../pyrung python scratchpad/click-v4/captures/v4_capture.py
12
+ ```
13
+
14
+ Done so far: math, out, drum, pins (fixtures in `tests/fixtures/v4_captures/`, goldens `<group>__v4` in
15
+ `tests/fixtures/coverage/golden/`). loop: Break/Continue taken from a hand capture (`loop_exits.bin`); the
16
+ `loop__v4` golden (the whole group, real Break/Continue) is paste-verified, so `stubs/loop.csv` needs no copy-back.
17
+
18
+ ## Per group
19
+
20
+ Run clicknick against the local checkouts (`make install-dev` in clicknick once, then `UV_NO_SYNC=1` and
21
+ `uv run --no-sync`). From the clicknick directory:
22
+
23
+ 1. `clicknick-rung load ../laddercodec/scratchpad/click-v4/captures/stubs/<group>.csv`, then paste into CLICK v4.
24
+ 2. Build each rung from its comment (see "What to do" below), then Syntax Check.
25
+ 3. Select all the group's rungs and copy them, then
26
+ `clicknick-rung save ../laddercodec/scratchpad/click-v4/captures/copyback/<group>`
27
+ (this writes `<group>.bin` and `<group>.csv`; keep it out of `stubs/`, which the generator rewrites;
28
+ `save` does not create `copyback/`).
29
+ Once every rung matches its comment or decodes as `raw(...)`, copy the `.bin` to
30
+ `tests/fixtures/v4_captures/` and delete the copy-back.
31
+ 4. In laddercodec, `make test`: rungs still decoded as `raw(...)` are xfail, and any other mismatch fails.
32
+
33
+ What to do in CLICK:
34
+
35
+ | Group | Placeholder | What to do |
36
+ |---|---|---|
37
+ | out | NOP | Replace it with Out using the variant in the comment. `on_acc=TD5` means TD5 in the dialog. |
38
+ | drum | v3 Time drum | Change the base to Time & Event. Set each event; blank the preset where the comment says `None`, and enter `DS....` where it names a register. |
39
+ | drum `time_ds*` | real instruction | Nothing, unless the paste is rejected. |
40
+ | math | real instruction | Nothing, unless the paste is rejected. If it is, rebuild it from the comment. |
41
+ | loop | NOP on a contacted body rung | Replace it with Break or Continue, as the rung's comment says. The other rungs are real. |
42
+ | pins | real instruction, each pin fed by one contact | The id names the OR'd pin(s). Under each, insert a row per extra leg and OR in the next contact up (see `expected/pins.csv`): `drum_reset_or` +1 leg on Reset, `drum_reset_or3` +2 on Reset, `drum_jump_or` +1 on Jump, `drum_all_or` +1 on each pin, `count_up_down_or` +1 on Down, `shift_clock_or` +1 on Clock. Let the box grow. Don't route a leg back up past the next pin. |
43
+
44
+ Math comments use CLICK's spelling, `NAME ( a , b )` (`SUM ( ... : ... )` and `RAND ( DD111 , DD112 )` are seen
45
+ natively; `ABS ( x )` is inferred). The `math__rand_*` bodies are stand-ins (pyrung has no `randint` yet) with
46
+ the token written by hand. Whatever the copy-back decodes to is the answer; fix the expected line to match.
47
+
48
+ A loop case is several rungs (For, body rungs, Next), each labelled `<id>/<k>` with its own AF tokens. Copy
49
+ every rung of the group back, Next rungs included.
50
+
51
+ ## Address map
52
+
53
+ | Group | Contacts | Targets / outputs | Timers | Data |
54
+ |---|---|---|---|---|
55
+ | out | C1001–C1020 | C1101–C1117, Y001–Y003 | T1–T24 / TD1–TD24 | DS1001–DS1006 (presets) |
56
+ | drum | C1201–C1207 | C1311–C1372 (C13n1.. for drum n) | TD101–TD107 (accumulators) | DS1201–DS1207 (step), DS1210 (jump step), DS1301–DS1304 (durations); done C1401–C1407; events C1501–C1509; reset/jog/jump C1601–C1609 |
57
+ | math | C1701–C1723 | DS1501–DS1508, DD201–DD205, DF201–DF205, DH201–DH205 | — | DS1401–DS1412, DD101–DD112, DF101–DF111, DH101–DH106, C1801–C1816 |
58
+ | loop | C1901–C1906 (For rungs), C1921–C1926 (body rungs) | C1941–C1942 | — | DS1601–DS1613 (counters, limits) |
59
+ | pins | C1050–C1097 (rung n: enable C(1042+8n), pin legs the next 7) | C1021–C1024 (drum outputs), C1031–C1034 (done), C1041–C1048 (shift bits) | TD111–TD114, CT1/CTD1 | DS1701–DS1704 (step), DS1710 (jump step) |
60
+
61
+ T1–T40 are reserved for the Out family (C0112: an Out coil claims its whole timer number).