btsnoop-parser 0.1.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.
@@ -0,0 +1,3 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 kranthi
@@ -0,0 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: btsnoop-parser
3
+ Version: 0.1.0
4
+ Summary: Bluetooth HCI btsnoop log parser for Android
5
+ Author-email: Your Name <you@example.com>
6
+ License-Expression: MIT
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Dynamic: license-file
10
+
11
+ ### README.md
12
+
13
+ # btsnoop-parser
14
+
15
+ A Python library to parse and decode Android Bluetooth `btsnoop_hci.log` files.
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ pip install .
21
+ btsnoop_parser path/to/btsnoop_hci.log
22
+ ```
@@ -0,0 +1,12 @@
1
+ ### README.md
2
+
3
+ # btsnoop-parser
4
+
5
+ A Python library to parse and decode Android Bluetooth `btsnoop_hci.log` files.
6
+
7
+ ## Usage
8
+
9
+ ```bash
10
+ pip install .
11
+ btsnoop_parser path/to/btsnoop_hci.log
12
+ ```
@@ -0,0 +1,6 @@
1
+ from .core import parse_btsnoop_file
2
+ from .hci_decoder import decode_hci_packet
3
+
4
+ __all__ = ["parse_btsnoop_file", "decode_hci_packet"]
5
+
6
+
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,14 @@
1
+ import argparse
2
+ from .core import parse_btsnoop_file
3
+ from .hci_decoder import decode_hci_packet
4
+
5
+ def main():
6
+ parser = argparse.ArgumentParser(description="Parse Android btsnoop_hci.log files")
7
+ parser.add_argument("file", help="Path to btsnoop_hci.log")
8
+ parser.add_argument("--limit", type=int, default=10, help="Limit output")
9
+ args = parser.parse_args()
10
+
11
+ records = parse_btsnoop_file(args.file)
12
+ for r in records[:args.limit]:
13
+ decoded = decode_hci_packet(r['packet_type'], r['packet_data'])
14
+ print(f"[{r['timestamp']}] {r['direction']} {r['packet_type']} - {decoded}")
@@ -0,0 +1,14 @@
1
+ HCI_PACKET_TYPES = {
2
+ 0x01: "COMMAND",
3
+ 0x02: "ACL",
4
+ 0x03: "SCO",
5
+ 0x04: "EVENT",
6
+ 0xFF: "VENDOR"
7
+ }
8
+
9
+ HCI_OPCODE_NAMES = {
10
+ 0x0401: "Inquiry",
11
+ 0x0405: "Create Connection",
12
+ 0x0406: "Disconnect",
13
+ # Add more opcodes as needed
14
+ }
@@ -0,0 +1,40 @@
1
+ import struct
2
+ import datetime
3
+ from .constants import HCI_PACKET_TYPES
4
+
5
+ BTSNOOP_HEADER = b'btsnoop\0'
6
+ BTSNOOP_TIMESTAMP_OFFSET = 0x00E03AB44A676000
7
+
8
+
9
+ def parse_btsnoop_file(filename):
10
+ records = []
11
+ with open(filename, 'rb') as f:
12
+ if f.read(8) != BTSNOOP_HEADER:
13
+ raise ValueError("Invalid BTSnoop file header")
14
+ _ = struct.unpack('>II', f.read(8)) # version, datalink
15
+ f.read(8) # reserved
16
+
17
+ while True:
18
+ header = f.read(24)
19
+ if len(header) < 24:
20
+ break
21
+ orig_len, incl_len, flags, drops, timestamp = struct.unpack('>IIIIQ', header)
22
+ packet = f.read(incl_len)
23
+ if not packet:
24
+ break
25
+
26
+ ts = datetime.datetime(1, 1, 1) + datetime.timedelta(
27
+ microseconds=timestamp - BTSNOOP_TIMESTAMP_OFFSET
28
+ )
29
+
30
+ record = {
31
+ 'timestamp': ts,
32
+ 'flags': flags,
33
+ 'direction': 'RX' if flags == 1 else 'TX',
34
+ 'packet_type': HCI_PACKET_TYPES.get(packet[0], 'UNKNOWN'),
35
+ 'packet_data': packet[1:],
36
+ 'raw': packet
37
+ }
38
+ records.append(record)
39
+
40
+ return records
@@ -0,0 +1,27 @@
1
+ from .constants import HCI_OPCODE_NAMES
2
+
3
+ def decode_hci_packet(packet_type, data):
4
+ if packet_type == 'COMMAND':
5
+ opcode = int.from_bytes(data[0:2], 'little')
6
+ plen = data[2]
7
+ params = data[3:3+plen]
8
+ return {
9
+ 'type': 'COMMAND',
10
+ 'opcode': opcode,
11
+ 'name': HCI_OPCODE_NAMES.get(opcode, 'Unknown'),
12
+ 'params': params.hex()
13
+ }
14
+ elif packet_type == 'EVENT':
15
+ event_code = data[0]
16
+ plen = data[1]
17
+ params = data[2:2+plen]
18
+ return {
19
+ 'type': 'EVENT',
20
+ 'event_code': event_code,
21
+ 'params': params.hex()
22
+ }
23
+ else:
24
+ return {
25
+ 'type': packet_type,
26
+ 'raw': data.hex()
27
+ }
@@ -0,0 +1,2 @@
1
+ def test_placeholder():
2
+ assert True # Replace with actual tests later
@@ -0,0 +1,2 @@
1
+ def hexify(data):
2
+ return ' '.join(f'{b:02X}' for b in data)
@@ -0,0 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: btsnoop-parser
3
+ Version: 0.1.0
4
+ Summary: Bluetooth HCI btsnoop log parser for Android
5
+ Author-email: Your Name <you@example.com>
6
+ License-Expression: MIT
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Dynamic: license-file
10
+
11
+ ### README.md
12
+
13
+ # btsnoop-parser
14
+
15
+ A Python library to parse and decode Android Bluetooth `btsnoop_hci.log` files.
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ pip install .
21
+ btsnoop_parser path/to/btsnoop_hci.log
22
+ ```
@@ -0,0 +1,16 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ btsnoop_parser/__init__.py
5
+ btsnoop_parser/__main__.py
6
+ btsnoop_parser/cli.py
7
+ btsnoop_parser/constants.py
8
+ btsnoop_parser/core.py
9
+ btsnoop_parser/hci_decoder.py
10
+ btsnoop_parser/utils.py
11
+ btsnoop_parser.egg-info/PKG-INFO
12
+ btsnoop_parser.egg-info/SOURCES.txt
13
+ btsnoop_parser.egg-info/dependency_links.txt
14
+ btsnoop_parser.egg-info/entry_points.txt
15
+ btsnoop_parser.egg-info/top_level.txt
16
+ btsnoop_parser/tests/test_parser.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ btsnoop_parser = btsnoop_parser.cli:main
@@ -0,0 +1 @@
1
+ btsnoop_parser
@@ -0,0 +1,15 @@
1
+ [project]
2
+ name = "btsnoop-parser"
3
+ version = "0.1.0"
4
+ description = "Bluetooth HCI btsnoop log parser for Android"
5
+ authors = [{name="Your Name", email="you@example.com"}]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+ dependencies = []
9
+
10
+ [project.scripts]
11
+ btsnoop_parser = "btsnoop_parser.cli:main"
12
+
13
+ [build-system]
14
+ requires = ["setuptools", "wheel"]
15
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+