summaryrefslogtreecommitdiffstats
path: root/freestyle_hid/tools/hid_console.py
blob: a9a133c5353ae762a6e093cb305d837736ac14ca (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env python3
# SPDX-FileCopyrightText: © 2019 The freestyle-hid Authors
# SPDX-License-Identifier: Apache-2.0
"""CLI tool to send messages through FreeStyle HID protocol."""

import logging
import pathlib
import sys
from typing import Optional

import click
import click_log

import freestyle_hid

logger = logging.getLogger()
click_log.basic_config(logger)


@click.command()
@click_log.simple_verbosity_option(logger, "--vlog")
@click.option(
    "--text-command-type",
    "-c",
    type=int,
    default=0x60,
    help="Message type for text commands sent to the device.",
)
@click.option(
    "--text-reply-type",
    "-r",
    type=int,
    default=0x60,
    help="Message type for text replies received from the device.",
)
@click.option(
    "--product-id",
    "-p",
    type=int,
    help="Optional product ID (in alternative to the device path)",
)
@click.option(
    "--encoding",
    "-e",
    type=str,
    help="Encoding to use to decode commands returned by the meter",
    default="ascii",
)
@click.option(
    "--encrypted-protocol / --no-encrypted-protocol",
    default=False,
    help=(
        "Whether to use the encrypted protocol to communicate to the device."
        " This is necessary to talk to Libre2 glucometers."
    ),
)
@click.argument(
    "device-path",
    type=click.Path(exists=True, dir_okay=False, writable=True, allow_dash=False),
    callback=lambda ctx, param, value: pathlib.Path(value) if value else None,
    required=False,
)
@click.argument(
    "command",
    type=str,
    required=False,
)
def main(
    *,
    text_command_type: int,
    text_reply_type: int,
    product_id: Optional[int],
    device_path: Optional[pathlib.Path],
    encoding: str,
    encrypted_protocol: bool,
    command: Optional[str],
):
    if not product_id and not device_path:
        raise click.UsageError(
            "One of --product-id or DEVICE_PATH need to be provided."
        )

    session = freestyle_hid.Session(
        product_id,
        device_path,
        text_command_type,
        text_reply_type,
        encoding=encoding,
        encrypted=encrypted_protocol,
    )

    session.connect()

    if command is not None:
        try:
            print(session.send_text_command(bytes(command, "ascii")))
        except freestyle_hid.CommandError as error:
            print(f"! {error!r}")

        return

    while True:
        if sys.stdin.isatty():
            command = input(">>> ")
        else:
            command = input()
            print(f">>> {command}")

        try:
            print(session.send_text_command(bytes(command, "ascii")))
        except freestyle_hid.CommandError as error:
            print(f"! {error!r}")


if __name__ == "__main__":
    main()