# {py:mod}`haniwers.v1.cli.scan`

```{py:module} haniwers.v1.cli.scan
```

```{autodoc2-docstring} haniwers.v1.cli.scan
:allowtitles:
```

## Module Contents

### Classes

````{list-table}
:class: autosummary longtable
:align: left

* - {py:obj}`ScanResult <haniwers.v1.cli.scan.ScanResult>`
  - ```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult
    :summary:
    ```
````

### Functions

````{list-table}
:class: autosummary longtable
:align: left

* - {py:obj}`aggregate_scan_result <haniwers.v1.cli.scan.aggregate_scan_result>`
  - ```{autodoc2-docstring} haniwers.v1.cli.scan.aggregate_scan_result
    :summary:
    ```
* - {py:obj}`save_scan_result <haniwers.v1.cli.scan.save_scan_result>`
  - ```{autodoc2-docstring} haniwers.v1.cli.scan.save_scan_result
    :summary:
    ```
* - {py:obj}`serial <haniwers.v1.cli.scan.serial>`
  - ```{autodoc2-docstring} haniwers.v1.cli.scan.serial
    :summary:
    ```
````

### Data

````{list-table}
:class: autosummary longtable
:align: left

* - {py:obj}`scan_app <haniwers.v1.cli.scan.scan_app>`
  - ```{autodoc2-docstring} haniwers.v1.cli.scan.scan_app
    :summary:
    ```
````

### API

````{py:data} scan_app
:canonical: haniwers.v1.cli.scan.scan_app
:value: >
   'Typer(...)'

```{autodoc2-docstring} haniwers.v1.cli.scan.scan_app
```

````

`````{py:class} ScanResult(/, **data: typing.Any)
:canonical: haniwers.v1.cli.scan.ScanResult

Bases: {py:obj}`pydantic.BaseModel`

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult
```

```{rubric} Initialization
```

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.__init__
```

````{py:attribute} timestamp
:canonical: haniwers.v1.cli.scan.ScanResult.timestamp
:type: datetime.datetime
:value: >
   None

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.timestamp
```

````

````{py:attribute} channel
:canonical: haniwers.v1.cli.scan.ScanResult.channel
:type: int
:value: >
   'Field(...)'

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.channel
```

````

````{py:attribute} vth
:canonical: haniwers.v1.cli.scan.ScanResult.vth
:type: int
:value: >
   'Field(...)'

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.vth
```

````

````{py:attribute} duration
:canonical: haniwers.v1.cli.scan.ScanResult.duration
:type: int
:value: >
   'Field(...)'

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.duration
```

````

````{py:attribute} counts
:canonical: haniwers.v1.cli.scan.ScanResult.counts
:type: int
:value: >
   'Field(...)'

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.counts
```

````

````{py:attribute} hit_top
:canonical: haniwers.v1.cli.scan.ScanResult.hit_top
:type: int
:value: >
   'Field(...)'

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.hit_top
```

````

````{py:attribute} hit_mid
:canonical: haniwers.v1.cli.scan.ScanResult.hit_mid
:type: int
:value: >
   'Field(...)'

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.hit_mid
```

````

````{py:attribute} hit_btm
:canonical: haniwers.v1.cli.scan.ScanResult.hit_btm
:type: int
:value: >
   'Field(...)'

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.hit_btm
```

````

````{py:attribute} tmp
:canonical: haniwers.v1.cli.scan.ScanResult.tmp
:type: float
:value: >
   None

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.tmp
```

````

````{py:attribute} atm
:canonical: haniwers.v1.cli.scan.ScanResult.atm
:type: float
:value: >
   None

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.atm
```

````

````{py:attribute} hmd
:canonical: haniwers.v1.cli.scan.ScanResult.hmd
:type: float
:value: >
   None

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.hmd
```

````

````{py:method} to_csv_row() -> list
:canonical: haniwers.v1.cli.scan.ScanResult.to_csv_row

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.to_csv_row
```

````

````{py:method} csv_header() -> list[str]
:canonical: haniwers.v1.cli.scan.ScanResult.csv_header
:classmethod:

```{autodoc2-docstring} haniwers.v1.cli.scan.ScanResult.csv_header
```

````

`````

````{py:function} aggregate_scan_result(events: list[haniwers.v1.daq.model.RawEvent], channel: int, vth: int, duration: int) -> typing.Optional[haniwers.v1.cli.scan.ScanResult]
:canonical: haniwers.v1.cli.scan.aggregate_scan_result

```{autodoc2-docstring} haniwers.v1.cli.scan.aggregate_scan_result
```
````

````{py:function} save_scan_result(csv_path: pathlib.Path, result: haniwers.v1.cli.scan.ScanResult) -> None
:canonical: haniwers.v1.cli.scan.save_scan_result

```{autodoc2-docstring} haniwers.v1.cli.scan.save_scan_result
```
````

````{py:function} serial(ctx: typer.Context, config: typing.Optional[pathlib.Path] = typer.Option(None, '--config', help='Configuration file path (config.toml, etc). If not specified, ConfigLoader searches default locations.'), port: typing.Optional[str] = typer.Option(None, '--port', help="Serial port path for OSECHI detector (e.g., /dev/ttyUSB0, COM3). Use 'haniwers-v1 port list' to find available ports.", rich_help_panel='Device Settings'), baudrate: typing.Optional[int] = typer.Option(None, '--baudrate', min=1, help='Serial communication baud rate in bits per second (e.g., 9600, 115200).', rich_help_panel='Device Settings'), timeout: typing.Optional[float] = typer.Option(None, '--timeout', min=0.1, help='Serial read timeout in seconds (e.g., 1.0, 2.0).', rich_help_panel='Device Settings'), device_label: typing.Optional[str] = typer.Option(None, '--device-label', help='Device identifier label for logging and documentation.', rich_help_panel='Device Settings'), thresholds: str = typer.Option(..., '--thresholds', '-t', help="Threshold configuration: 'channel:threshold;channel:threshold;...'. Examples: '1:290' (single channel), '1:290;2:320;3:298' (all channels).", rich_help_panel='Scan Settings'), nsteps: typing.Optional[int] = typer.Option(10, '--nsteps', min=1, help='Number of steps on each side of center (default: 10).', rich_help_panel='Scan Settings'), step: typing.Optional[int] = typer.Option(1, '--step', min=1, help='Threshold increment between measurement points (default: 1).', rich_help_panel='Scan Settings'), duration: typing.Optional[int] = typer.Option(10, '--duration', min=1, help='Measurement duration per threshold in seconds (default: 10).', rich_help_panel='Scan Settings'), suppress: typing.Optional[int] = typer.Option(1000, '--suppress', min=1, max=1023, help='Threshold value for non-target channels (default: 1000).', rich_help_panel='Scan Settings'), max_retry: int = typer.Option(3, '--max-retry', min=1, help='Maximum number of retry attempts on communication failure (default: 3).', rich_help_panel='Scan Settings'), history: pathlib.Path = typer.Option('threshold_history.csv', '--history', help='Audit log file for threshold operations (CSV format with timestamp). Automatically saved in workspace directory.', rich_help_panel='Scan Settings'), workspace: typing.Optional[pathlib.Path] = typer.Option(None, '--workspace', help='Output directory for data files. Timestamped subdirectory created automatically.', rich_help_panel='Output Settings'), filename_prefix: typing.Optional[str] = typer.Option('scan_data', '--filename-prefix', help="Prefix for output file names (default: 'scan_data').", rich_help_panel='Output Settings'), filename_suffix: typing.Optional[str] = typer.Option(None, '--filename-suffix', help="File extension/suffix for output files (e.g., '.csv').", rich_help_panel='Output Settings'), events_per_file: typing.Optional[int] = typer.Option(1000, '--events-per-file', min=1, help='Number of detector events per output file before rollover (default: 1000).', rich_help_panel='Output Settings'), number_of_files: typing.Optional[int] = typer.Option(1, '--number-of-files', min=1, help='Maximum number of files to create per threshold level (default: 1).', rich_help_panel='Output Settings'), stream_mode: bool = typer.Option(False, '--stream-mode', help='Enable continuous streaming mode (output buffering disabled).', rich_help_panel='Output Settings'), daq_label: typing.Optional[str] = typer.Option(None, '--daq-label', help='Session identifier label for this DAQ run.', rich_help_panel='Output Settings'), mock: bool = typer.Option(False, '--mock', help='Use RandomMocker instead of real device for testing (no hardware required).', rich_help_panel='Testing')) -> None
:canonical: haniwers.v1.cli.scan.serial

```{autodoc2-docstring} haniwers.v1.cli.scan.serial
```
````
