firestarter 3.2.0__tar.gz → 3.2.1__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.
- {firestarter-3.2.0/firestarter.egg-info → firestarter-3.2.1}/PKG-INFO +2 -1
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/_version.py +3 -3
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/cli_handlers.py +4 -4
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/diagnostic_report.py +4 -4
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/eprom_operations.py +6 -6
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/firmware.py +3 -2
- firestarter-3.2.1/firestarter/timestamps.py +83 -0
- {firestarter-3.2.0 → firestarter-3.2.1/firestarter.egg-info}/PKG-INFO +2 -1
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter.egg-info/SOURCES.txt +3 -9
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter.egg-info/requires.txt +1 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter.egg-info/scm_file_list.json +3 -9
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter.egg-info/scm_version.json +2 -2
- {firestarter-3.2.0 → firestarter-3.2.1}/pyproject.toml +1 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/conftest.py +35 -0
- firestarter-3.2.0/tests/golden/wire_dict_baseline.json → firestarter-3.2.1/tests/golden/wire_dict.json +189 -137
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_derive_plan_no_drop_sweep.py +14 -22
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_devtest_firmware_error_propagation.py +11 -4
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_erase_flag_invariants.py +20 -30
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_firmware_install.py +4 -2
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_hardware.py +10 -2
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_page_size_invariants.py +22 -44
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_probe_spurious_setup_ack.py +3 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_protocol_not_implemented_production_path.py +4 -1
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_sdp_db_invariant.py +22 -62
- firestarter-3.2.1/tests/test_timestamps.py +87 -0
- firestarter-3.2.1/tests/test_wire_dict_equivalence.py +177 -0
- firestarter-3.2.0/tests/golden/wire_dict_expected_deltas_149.json +0 -65
- firestarter-3.2.0/tests/golden/wire_dict_expected_deltas_153.json +0 -265
- firestarter-3.2.0/tests/golden/wire_dict_expected_deltas_182.json +0 -219
- firestarter-3.2.0/tests/golden/wire_dict_expected_deltas_194.json +0 -86
- firestarter-3.2.0/tests/golden/wire_dict_expected_deltas_197.json +0 -20
- firestarter-3.2.0/tests/golden/wire_dict_expected_deltas_198.json +0 -17
- firestarter-3.2.0/tests/golden/wire_dict_expected_deltas_199.json +0 -14
- firestarter-3.2.0/tests/golden/wire_dict_expected_deltas_dip24_2816.json +0 -91
- firestarter-3.2.0/tests/test_wire_dict_equivalence.py +0 -821
- {firestarter-3.2.0 → firestarter-3.2.1}/LICENSE +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/MANIFEST.in +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/README.md +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/__init__.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/address_parser.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/avr_tool.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/channel.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/chip_resolver.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/chip_test.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/codec.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/compare.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/config.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/constants.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/data/chip_database.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/data/pinouts.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/database.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/dip24_2816_erase_gate.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/eprom_info.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/erase_support.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/exceptions.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/flash4_erase_gate.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/frame_parser.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/fw_release_gate.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/hardware.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/ic_layout.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/jp5_gate.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/jumper_table.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/lock_status.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/log_capture.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/logging_utils.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/main.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/messages.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/page_size_gate.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/protection_readability.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/py32_dfu.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/sdp_capability.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/sdp_honesty.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/serial_comm.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/submit.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/transport_counters.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/utils.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/vpp_display.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter/write_blank_guard.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter.egg-info/dependency_links.txt +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter.egg-info/entry_points.txt +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/firestarter.egg-info/top_level.txt +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/setup.cfg +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/__init__.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/__snapshots__/test_characterization.ambr +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fake_chip.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/part_number_delta.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/report_shapes.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/at28c256-full-all-ok-sdp.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/attr01-status-axis-transport-fault.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/gh20-at28c256-fail.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/gh23-w27e257-fail.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/gh28-m27c512-fail.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/gh47-sst27sf512-pass.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/m27c512-full-all-ok.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/m27c512-full-blank-check-bad.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/m27c512-full-canonical-name.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/m27c512-full-comma-joined-name.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/m27c512-full-runs-1.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/prune03-synthesized-fingerprint-match.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/sst27sf512-full-all-ok.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/sst27sf512-six-step-readback-gated.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/sst27sf512-six-step.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/synthetic-arm4-empty-results.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/synthetic-arm4-no-ok.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/uv-slot-write-pass.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/reports/w27e257-full-all-ok.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/shape_ids.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/fixtures/synthetic_nonzero_chip_id.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/golden/build_db_part_specific_constants.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/golden/chip_database_field_inventory.json +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/plan_corpus.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_address_parser.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_b15_page_size_corroboration.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_blast_radius_invariance.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_boot_block_hint.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_budget_failure_render.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_bug_characterization.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_build_db_constant_census.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_build_db_inclusion.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_build_db_interpret_timing.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_build_db_pinout_fork.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_canonical_part_number.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_characterization.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_chip_database_field_inventory.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_chip_resolver.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_chip_test.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_chip_test_blank_check_order.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_chip_test_cycle.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_chip_test_sdp_leg.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_chip_test_timing.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_chip_test_uv_slot_write.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_cli_handlers.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_click_group_gate_hook.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_cobs.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_codec.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_codec_format_message.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_compare.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_config.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_config_band_refusal.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_connect_cost_harness.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_consistency_check.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_coverage_floor_v18.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_database_conversion.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_datasheet_overrides.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_decoder.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_derive_plan_structural_sentinel.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_dev_group_channel_gating.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_dev_test_cmd.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_dev_tools_channel_gate.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_dfu_opcode_anchors.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_diagnostic_report.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_dip24_2816_erase_gate.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_endpoint_constants.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_eprom_database.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_eprom_info.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_eprom_operations.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_erase_blank_step_nonregression.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_error_code_seam.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_even_block.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_extra_chips_supplement.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_flash4_erase_gate.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_fw_list_failure_vs_empty.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_fw_port_targeting_and_blind_install.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_fw_release_gate.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_fw_update_dead_endpoint.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_fw_update_path_gate.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_fw_version_guard.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_fwguard.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_hw_revision_gate.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_ic_layout.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_info_vpp_and_erase.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_jp5_gate.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_jumper_table.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_lock_status_class_partition.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_lock_status_cli.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_lock_status_wire.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_log_capture.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_logging_utils.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_matrix_artifact.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_page_size_alignment_refusal.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_page_size_write_refusal.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_parse_devtest_issue.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_programming_vcc_census.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_protect_flags_doc_measurements.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_protection_resolution.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_protection_status_catalog.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_protection_table_citations.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_protocol_not_implemented.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_provenance.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_pulse_us_override.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_py32_channel_gating.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_py32_dfu.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_py32_flash_map_host.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_py32_pyusb_absent.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_pyusb_api_surface.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_sdp_capability.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_sdp_honesty.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_serial_characterization.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_serial_comm.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_session_lease.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_setup_refusals.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_submit.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_transport_counters.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_utils.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_uv_mask.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_validate_family_cmd.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_validate_oracle.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_validated_parts_regression_surface.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_vcc_margin_rail.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_vpp_decode_table.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_vpp_rail_classification.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_write_blank_guard.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_write_blank_guard_pinning.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_write_guard_port_pinning.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_write_progress.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_write_response_budget.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_write_skip_erase_0x0d.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_write_skip_sdp_unlock.py +0 -0
- {firestarter-3.2.0 → firestarter-3.2.1}/tests/test_write_verify.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: firestarter
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.1
|
|
4
4
|
Summary: EPROM programmer software for the Relatively Universal ROM Programmer
|
|
5
5
|
Author-email: Henrik Olsson <henols@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/henols/firestarter_app
|
|
@@ -37,6 +37,7 @@ Requires-Dist: syrupy<7,>=5.0; extra == "test"
|
|
|
37
37
|
Requires-Dist: ruff>=0.15.14; extra == "test"
|
|
38
38
|
Requires-Dist: mypy<3,>=2.1.0; extra == "test"
|
|
39
39
|
Requires-Dist: pytest-cov>=7.1.0; extra == "test"
|
|
40
|
+
Requires-Dist: pytest-xdist>=3.6; extra == "test"
|
|
40
41
|
Requires-Dist: types-pyserial>=3.5.0.20260519; extra == "test"
|
|
41
42
|
Dynamic: license-file
|
|
42
43
|
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '3.2.
|
|
22
|
-
__version_tuple__ = version_tuple = (3, 2,
|
|
21
|
+
__version__ = version = '3.2.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (3, 2, 1)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g4526a89'
|
|
@@ -4,7 +4,6 @@ This module is the production CLI surface; main.py re-exports `cli` as `main`
|
|
|
4
4
|
for the console-script entry point.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
import datetime
|
|
8
7
|
import functools
|
|
9
8
|
import hashlib
|
|
10
9
|
import json
|
|
@@ -106,6 +105,7 @@ from firestarter.protection_readability import (
|
|
|
106
105
|
protection_gate_for_entry,
|
|
107
106
|
)
|
|
108
107
|
from firestarter.sdp_capability import SDP_PROTOCOL_ID, sdp_capability
|
|
108
|
+
from firestarter.timestamps import iso_cet
|
|
109
109
|
|
|
110
110
|
logger = logging.getLogger("Firestarter")
|
|
111
111
|
|
|
@@ -1908,10 +1908,10 @@ def fw(
|
|
|
1908
1908
|
|
|
1909
1909
|
print(_json.dumps(releases, indent=2))
|
|
1910
1910
|
else:
|
|
1911
|
-
print(f"{'Version':<12} {'Channel':<14} {'Published':<
|
|
1911
|
+
print(f"{'Version':<12} {'Channel':<14} {'Published':<25} Asset URL")
|
|
1912
1912
|
for r in releases:
|
|
1913
1913
|
print(
|
|
1914
|
-
f"{r['version']:<12} {r['channel']:<14} {r['published']:<
|
|
1914
|
+
f"{r['version']:<12} {r['channel']:<14} {r['published']:<25} {r['asset_url']}" # noqa: E501
|
|
1915
1915
|
)
|
|
1916
1916
|
if not releases:
|
|
1917
1917
|
print(f"No releases found for board {board}.")
|
|
@@ -2638,7 +2638,7 @@ def _write_artifact(
|
|
|
2638
2638
|
out_path.mkdir(parents=True, exist_ok=True)
|
|
2639
2639
|
|
|
2640
2640
|
artifact: Dict[str, Any] = { # noqa: UP006
|
|
2641
|
-
"generated":
|
|
2641
|
+
"generated": iso_cet(),
|
|
2642
2642
|
"harness_version": "71",
|
|
2643
2643
|
"cells": cells,
|
|
2644
2644
|
}
|
|
@@ -23,7 +23,6 @@ human-input field gates it.
|
|
|
23
23
|
|
|
24
24
|
from __future__ import annotations
|
|
25
25
|
|
|
26
|
-
import datetime
|
|
27
26
|
import hashlib
|
|
28
27
|
import json
|
|
29
28
|
from dataclasses import dataclass, field
|
|
@@ -45,6 +44,7 @@ from firestarter.chip_test import (
|
|
|
45
44
|
repeat_policy_tag,
|
|
46
45
|
resolve_error_name,
|
|
47
46
|
)
|
|
47
|
+
from firestarter.timestamps import iso_cet
|
|
48
48
|
|
|
49
49
|
# ---------------------------------------------------------------------------
|
|
50
50
|
# Module constants -- single sources of truth
|
|
@@ -774,8 +774,8 @@ class DiagnosticReport:
|
|
|
774
774
|
over dataclass fields, so this field's absence from that list is the
|
|
775
775
|
whole exclusion mechanism."""
|
|
776
776
|
|
|
777
|
-
def
|
|
778
|
-
return
|
|
777
|
+
def _now(self) -> str:
|
|
778
|
+
return iso_cet()
|
|
779
779
|
|
|
780
780
|
def _auto_capture_dict(self) -> dict[str, Any]:
|
|
781
781
|
ac = self.auto_capture
|
|
@@ -1065,7 +1065,7 @@ class DiagnosticReport:
|
|
|
1065
1065
|
"""
|
|
1066
1066
|
return {
|
|
1067
1067
|
"schema_version": SCHEMA_VERSION,
|
|
1068
|
-
"generated": self.
|
|
1068
|
+
"generated": self._now(),
|
|
1069
1069
|
"elapsed": self.elapsed,
|
|
1070
1070
|
"auto_capture": self._auto_capture_dict(),
|
|
1071
1071
|
"transport_health": self._transport_dict(),
|
|
@@ -15,7 +15,6 @@ import shutil
|
|
|
15
15
|
import statistics
|
|
16
16
|
import time
|
|
17
17
|
from contextlib import contextmanager
|
|
18
|
-
from datetime import datetime
|
|
19
18
|
from pathlib import Path
|
|
20
19
|
from typing import Callable, Dict, Tuple # noqa: UP035
|
|
21
20
|
|
|
@@ -75,6 +74,7 @@ from firestarter.serial_comm import (
|
|
|
75
74
|
WRITE_BUDGET_MAX_S,
|
|
76
75
|
SerialCommunicator,
|
|
77
76
|
)
|
|
77
|
+
from firestarter.timestamps import iso_cet_basic
|
|
78
78
|
from firestarter.utils import extract_hex_to_decimal
|
|
79
79
|
from firestarter.write_blank_guard import (
|
|
80
80
|
incomplete_refusal_text,
|
|
@@ -1383,7 +1383,7 @@ class EpromOperator:
|
|
|
1383
1383
|
# path is to use the actual board name -- but the unit-test
|
|
1384
1384
|
# surface doesn't have a serial connection, so we fall back).
|
|
1385
1385
|
if output_dir is None:
|
|
1386
|
-
timestamp =
|
|
1386
|
+
timestamp = iso_cet_basic()
|
|
1387
1387
|
output_dir = str(
|
|
1388
1388
|
Path(DEFAULT_RUN_OUTPUT_DIR)
|
|
1389
1389
|
/ f"consistency-check-{eprom_name}-unknown-board-{timestamp}"
|
|
@@ -1560,7 +1560,7 @@ class EpromOperator:
|
|
|
1560
1560
|
source_sha = hashlib.sha256(Path(source_image_path).read_bytes()).hexdigest()
|
|
1561
1561
|
|
|
1562
1562
|
if output_dir is None:
|
|
1563
|
-
timestamp =
|
|
1563
|
+
timestamp = iso_cet_basic()
|
|
1564
1564
|
output_dir = str(
|
|
1565
1565
|
Path(DEFAULT_RUN_OUTPUT_DIR)
|
|
1566
1566
|
/ f"write-cycle-{eprom_name}-unknown-board-{timestamp}"
|
|
@@ -1678,7 +1678,7 @@ class EpromOperator:
|
|
|
1678
1678
|
from firestarter.serial_comm import FaultInjectingSerialCommunicator
|
|
1679
1679
|
|
|
1680
1680
|
if output_dir is None:
|
|
1681
|
-
timestamp =
|
|
1681
|
+
timestamp = iso_cet_basic()
|
|
1682
1682
|
output_dir = f"fault-inject-{eprom_name}-{direction}-{timestamp}"
|
|
1683
1683
|
output_path = Path(output_dir)
|
|
1684
1684
|
output_path.mkdir(parents=True, exist_ok=True)
|
|
@@ -1945,7 +1945,7 @@ class EpromOperator:
|
|
|
1945
1945
|
return False
|
|
1946
1946
|
|
|
1947
1947
|
if output_dir is None:
|
|
1948
|
-
timestamp =
|
|
1948
|
+
timestamp = iso_cet_basic()
|
|
1949
1949
|
output_dir = f"fault-inject-latency-{fault_form}-{timestamp}"
|
|
1950
1950
|
output_path = Path(output_dir)
|
|
1951
1951
|
output_path.mkdir(parents=True, exist_ok=True)
|
|
@@ -2149,7 +2149,7 @@ class EpromOperator:
|
|
|
2149
2149
|
return False
|
|
2150
2150
|
|
|
2151
2151
|
if output_dir is None:
|
|
2152
|
-
timestamp =
|
|
2152
|
+
timestamp = iso_cet_basic()
|
|
2153
2153
|
output_dir = f"connect-cost-{timestamp}"
|
|
2154
2154
|
output_path = Path(output_dir)
|
|
2155
2155
|
output_path.mkdir(parents=True, exist_ok=True)
|
|
@@ -41,6 +41,7 @@ from firestarter.exceptions import (
|
|
|
41
41
|
)
|
|
42
42
|
from firestarter.fw_release_gate import require_installable_release
|
|
43
43
|
from firestarter.serial_comm import SerialCommunicator
|
|
44
|
+
from firestarter.timestamps import iso_text_to_cet
|
|
44
45
|
|
|
45
46
|
logger = logging.getLogger("Firmware")
|
|
46
47
|
|
|
@@ -62,7 +63,7 @@ class ReleaseInfo(TypedDict):
|
|
|
62
63
|
version: str # tag_name from GitHub API
|
|
63
64
|
tag: str # raw tag_name (same as version for firmware releases)
|
|
64
65
|
channel: str # "stable" or "prerelease"
|
|
65
|
-
published: str # ISO
|
|
66
|
+
published: str # published_at as ISO 8601 in CET
|
|
66
67
|
asset_url: str # browser_download_url for the board-matching .hex asset
|
|
67
68
|
|
|
68
69
|
|
|
@@ -468,7 +469,7 @@ class FirmwareManager:
|
|
|
468
469
|
version=tag,
|
|
469
470
|
tag=tag,
|
|
470
471
|
channel="prerelease" if is_pre else "stable",
|
|
471
|
-
published=r.get("published_at") or "",
|
|
472
|
+
published=iso_text_to_cet(r.get("published_at") or ""),
|
|
472
473
|
asset_url=asset_url,
|
|
473
474
|
)
|
|
474
475
|
)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Name: Firestarter
|
|
3
|
+
Copyright (c) 2024 Henrik Olsson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted under MIT license.
|
|
6
|
+
|
|
7
|
+
Timestamp Formatting Module
|
|
8
|
+
|
|
9
|
+
Every timestamp the host writes is ISO 8601 in Central European Time: CET
|
|
10
|
+
(UTC+01:00) in winter and CEST (UTC+02:00) during EU summer time. Summer time
|
|
11
|
+
starts on the last Sunday of March and ends on the last Sunday of October, at
|
|
12
|
+
01:00 UTC both times.
|
|
13
|
+
|
|
14
|
+
The EU rule is computed here instead of through `zoneinfo`, because Windows
|
|
15
|
+
and slim Linux images have no tz database and the app does not depend on the
|
|
16
|
+
`tzdata` package.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import datetime
|
|
22
|
+
|
|
23
|
+
_CET = datetime.timezone(datetime.timedelta(hours=1), "CET")
|
|
24
|
+
_CEST = datetime.timezone(datetime.timedelta(hours=2), "CEST")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _last_sunday_0100_utc(year: int, month: int) -> datetime.datetime:
|
|
28
|
+
"""01:00 UTC on the last Sunday of `month` (March or October, both 31 days)."""
|
|
29
|
+
last_day = datetime.datetime(year, month, 31, 1, tzinfo=datetime.UTC)
|
|
30
|
+
return last_day - datetime.timedelta(days=(last_day.weekday() + 1) % 7)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def to_cet(moment: datetime.datetime) -> datetime.datetime:
|
|
34
|
+
"""Return `moment` converted to CET or CEST.
|
|
35
|
+
|
|
36
|
+
Raises ValueError for a naive `moment`, because its zone is unknown.
|
|
37
|
+
"""
|
|
38
|
+
if moment.tzinfo is None:
|
|
39
|
+
raise ValueError("to_cet() needs a timezone-aware datetime")
|
|
40
|
+
year = moment.astimezone(datetime.UTC).year
|
|
41
|
+
summer_start = _last_sunday_0100_utc(year, 3)
|
|
42
|
+
summer_end = _last_sunday_0100_utc(year, 10)
|
|
43
|
+
return moment.astimezone(_CEST if summer_start <= moment < summer_end else _CET)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def now_cet() -> datetime.datetime:
|
|
47
|
+
"""The current time in CET or CEST."""
|
|
48
|
+
return to_cet(datetime.datetime.now(datetime.UTC))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def iso_cet(moment: datetime.datetime | None = None) -> str:
|
|
52
|
+
"""ISO 8601 extended format, e.g. `2026-10-09T14:30:56+02:00`.
|
|
53
|
+
|
|
54
|
+
Uses the current time when `moment` is None.
|
|
55
|
+
"""
|
|
56
|
+
cet = now_cet() if moment is None else to_cet(moment)
|
|
57
|
+
return cet.isoformat(timespec="seconds")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def iso_cet_basic(moment: datetime.datetime | None = None) -> str:
|
|
61
|
+
"""ISO 8601 basic format for file and directory names, e.g.
|
|
62
|
+
`20261009T143056+0200`.
|
|
63
|
+
|
|
64
|
+
The basic format has no colons. Windows does not permit a colon in a path.
|
|
65
|
+
Uses the current time when `moment` is None.
|
|
66
|
+
"""
|
|
67
|
+
cet = now_cet() if moment is None else to_cet(moment)
|
|
68
|
+
return cet.strftime("%Y%m%dT%H%M%S%z")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def iso_text_to_cet(text: str) -> str:
|
|
72
|
+
"""Return the ISO 8601 timestamp `text` (e.g. GitHub's
|
|
73
|
+
`2026-01-01T00:00:00Z`) in CET, in extended format.
|
|
74
|
+
|
|
75
|
+
Returns `text` unchanged when it does not parse or has no UTC offset.
|
|
76
|
+
"""
|
|
77
|
+
try:
|
|
78
|
+
moment = datetime.datetime.fromisoformat(text)
|
|
79
|
+
except (TypeError, ValueError):
|
|
80
|
+
return text
|
|
81
|
+
if moment.tzinfo is None:
|
|
82
|
+
return text
|
|
83
|
+
return iso_cet(moment)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: firestarter
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.1
|
|
4
4
|
Summary: EPROM programmer software for the Relatively Universal ROM Programmer
|
|
5
5
|
Author-email: Henrik Olsson <henols@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/henols/firestarter_app
|
|
@@ -37,6 +37,7 @@ Requires-Dist: syrupy<7,>=5.0; extra == "test"
|
|
|
37
37
|
Requires-Dist: ruff>=0.15.14; extra == "test"
|
|
38
38
|
Requires-Dist: mypy<3,>=2.1.0; extra == "test"
|
|
39
39
|
Requires-Dist: pytest-cov>=7.1.0; extra == "test"
|
|
40
|
+
Requires-Dist: pytest-xdist>=3.6; extra == "test"
|
|
40
41
|
Requires-Dist: types-pyserial>=3.5.0.20260519; extra == "test"
|
|
41
42
|
Dynamic: license-file
|
|
42
43
|
|
|
@@ -41,6 +41,7 @@ firestarter/sdp_capability.py
|
|
|
41
41
|
firestarter/sdp_honesty.py
|
|
42
42
|
firestarter/serial_comm.py
|
|
43
43
|
firestarter/submit.py
|
|
44
|
+
firestarter/timestamps.py
|
|
44
45
|
firestarter/transport_counters.py
|
|
45
46
|
firestarter/utils.py
|
|
46
47
|
firestarter/vpp_display.py
|
|
@@ -159,6 +160,7 @@ tests/test_serial_comm.py
|
|
|
159
160
|
tests/test_session_lease.py
|
|
160
161
|
tests/test_setup_refusals.py
|
|
161
162
|
tests/test_submit.py
|
|
163
|
+
tests/test_timestamps.py
|
|
162
164
|
tests/test_transport_counters.py
|
|
163
165
|
tests/test_utils.py
|
|
164
166
|
tests/test_uv_mask.py
|
|
@@ -203,12 +205,4 @@ tests/fixtures/reports/uv-slot-write-pass.json
|
|
|
203
205
|
tests/fixtures/reports/w27e257-full-all-ok.json
|
|
204
206
|
tests/golden/build_db_part_specific_constants.json
|
|
205
207
|
tests/golden/chip_database_field_inventory.json
|
|
206
|
-
tests/golden/
|
|
207
|
-
tests/golden/wire_dict_expected_deltas_149.json
|
|
208
|
-
tests/golden/wire_dict_expected_deltas_153.json
|
|
209
|
-
tests/golden/wire_dict_expected_deltas_182.json
|
|
210
|
-
tests/golden/wire_dict_expected_deltas_194.json
|
|
211
|
-
tests/golden/wire_dict_expected_deltas_197.json
|
|
212
|
-
tests/golden/wire_dict_expected_deltas_198.json
|
|
213
|
-
tests/golden/wire_dict_expected_deltas_199.json
|
|
214
|
-
tests/golden/wire_dict_expected_deltas_dip24_2816.json
|
|
208
|
+
tests/golden/wire_dict.json
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"firestarter/sdp_honesty.py",
|
|
68
68
|
"firestarter/serial_comm.py",
|
|
69
69
|
"firestarter/submit.py",
|
|
70
|
+
"firestarter/timestamps.py",
|
|
70
71
|
"firestarter/transport_counters.py",
|
|
71
72
|
"firestarter/utils.py",
|
|
72
73
|
"firestarter/vpp_display.py",
|
|
@@ -103,15 +104,7 @@
|
|
|
103
104
|
"tests/fixtures/synthetic_nonzero_chip_id.py",
|
|
104
105
|
"tests/golden/build_db_part_specific_constants.json",
|
|
105
106
|
"tests/golden/chip_database_field_inventory.json",
|
|
106
|
-
"tests/golden/
|
|
107
|
-
"tests/golden/wire_dict_expected_deltas_149.json",
|
|
108
|
-
"tests/golden/wire_dict_expected_deltas_153.json",
|
|
109
|
-
"tests/golden/wire_dict_expected_deltas_182.json",
|
|
110
|
-
"tests/golden/wire_dict_expected_deltas_194.json",
|
|
111
|
-
"tests/golden/wire_dict_expected_deltas_197.json",
|
|
112
|
-
"tests/golden/wire_dict_expected_deltas_198.json",
|
|
113
|
-
"tests/golden/wire_dict_expected_deltas_199.json",
|
|
114
|
-
"tests/golden/wire_dict_expected_deltas_dip24_2816.json",
|
|
107
|
+
"tests/golden/wire_dict.json",
|
|
115
108
|
"tests/plan_corpus.py",
|
|
116
109
|
"tests/test_address_parser.py",
|
|
117
110
|
"tests/test_b15_page_size_corroboration.py",
|
|
@@ -213,6 +206,7 @@
|
|
|
213
206
|
"tests/test_session_lease.py",
|
|
214
207
|
"tests/test_setup_refusals.py",
|
|
215
208
|
"tests/test_submit.py",
|
|
209
|
+
"tests/test_timestamps.py",
|
|
216
210
|
"tests/test_transport_counters.py",
|
|
217
211
|
"tests/test_utils.py",
|
|
218
212
|
"tests/test_uv_mask.py",
|
|
@@ -37,6 +37,7 @@ from __future__ import annotations
|
|
|
37
37
|
|
|
38
38
|
import importlib.util
|
|
39
39
|
import io
|
|
40
|
+
import os
|
|
40
41
|
import struct
|
|
41
42
|
from typing import TYPE_CHECKING, cast
|
|
42
43
|
from unittest.mock import Mock
|
|
@@ -96,6 +97,40 @@ collect_ignore: list = []
|
|
|
96
97
|
if _pyusb_is_absent():
|
|
97
98
|
collect_ignore.append("test_pyusb_api_surface.py")
|
|
98
99
|
|
|
100
|
+
|
|
101
|
+
# `dev test` runs a `gh issue list --author @me` dedup query through
|
|
102
|
+
# `submit.find_prior_report`, bound as a default argument, so patching the
|
|
103
|
+
# module attribute does not reach it. A stub `gh` first on PATH answers every
|
|
104
|
+
# call as "not authenticated" (exit 4): no test waits on GitHub, depends on the
|
|
105
|
+
# developer's gh login, or branches on their real issues.
|
|
106
|
+
@pytest.fixture(autouse=True)
|
|
107
|
+
def _offline_gh(tmp_path_factory, monkeypatch):
|
|
108
|
+
bin_dir = tmp_path_factory.getbasetemp() / "offline-gh-bin"
|
|
109
|
+
gh = bin_dir / "gh"
|
|
110
|
+
if not gh.exists():
|
|
111
|
+
bin_dir.mkdir(exist_ok=True)
|
|
112
|
+
gh.write_text("#!/bin/sh\nexit 4\n")
|
|
113
|
+
gh.chmod(0o755)
|
|
114
|
+
monkeypatch.setenv("PATH", f"{bin_dir}{os.pathsep}{os.environ.get('PATH', '')}")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# `disconnect()` drains the port with `consume_remaining_input(timeout=0.5)`.
|
|
118
|
+
# A fake serial port answers every read at once, so the drain only ends when
|
|
119
|
+
# the window runs out: 0.5 s of wall time per disconnect, a full second for a
|
|
120
|
+
# write with a guard read. Any parsed frame restarts the window, so a short one
|
|
121
|
+
# still drains everything a test fed. An explicit timeout is kept.
|
|
122
|
+
@pytest.fixture(autouse=True)
|
|
123
|
+
def _short_drain_window(monkeypatch):
|
|
124
|
+
from firestarter.serial_comm import SerialCommunicator
|
|
125
|
+
|
|
126
|
+
drain = SerialCommunicator.consume_remaining_input
|
|
127
|
+
|
|
128
|
+
def _short_drain(self, timeout: float = 0.02) -> None:
|
|
129
|
+
drain(self, timeout)
|
|
130
|
+
|
|
131
|
+
monkeypatch.setattr(SerialCommunicator, "consume_remaining_input", _short_drain)
|
|
132
|
+
|
|
133
|
+
|
|
99
134
|
# Module-level reference constants — independent of firestarter.serial_comm
|
|
100
135
|
# so tests do not pass tautologically on a bug in the production constant.
|
|
101
136
|
MAGIC_PREAMBLE_REF: bytes = b"\xaa\x55\xaa\x55"
|