Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
93
tundra/tools/inspect-hardware.py
Normal file
93
tundra/tools/inspect-hardware.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
"""Read readiness, never dial, send messages, enter PINs or open camera nodes."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
|
||||
def command(args):
|
||||
try:
|
||||
result = subprocess.run(args, capture_output=True, text=True, timeout=12)
|
||||
if result.returncode:
|
||||
return None
|
||||
return result.stdout
|
||||
except (OSError, subprocess.TimeoutExpired):
|
||||
return None
|
||||
|
||||
|
||||
def bus(*args):
|
||||
text = command(['busctl', '--system', '--json=short', *args])
|
||||
try:
|
||||
return json.loads(text)['data'] if text is not None else None
|
||||
except (ValueError, KeyError, TypeError):
|
||||
return None
|
||||
|
||||
|
||||
def properties(interface):
|
||||
data = bus('call', 'org.ofono', '/ril_0', interface, 'GetProperties')
|
||||
if isinstance(data, list) and len(data) == 1:
|
||||
data = data[0]
|
||||
return data if isinstance(data, dict) else {}
|
||||
|
||||
|
||||
def selected(values, names):
|
||||
# GetProperties returns identifiers too: none are copied into the report.
|
||||
return {key: values[key].get('data') for key in names
|
||||
if key in values and isinstance(values[key], dict)}
|
||||
|
||||
|
||||
def inspect():
|
||||
native = 'tundra.rescue=1' in Path('/proc/cmdline').read_text()
|
||||
report = {'recordedAtUnix': time.time(), 'environment': 'tundra' if native else 'reference',
|
||||
'scope': 'Read-only readiness, not functional call/SMS/audio/camera qualification',
|
||||
'services': {}}
|
||||
for service in ('tundra-hal', 'tundra-wifi', 'NetworkManager', 'ofono', 'ModemManager'):
|
||||
report['services'][service] = (command(['systemctl', 'is-active', service]) or 'inactive').strip()
|
||||
modem = selected(properties('org.ofono.Modem'), ('Powered', 'Online', 'Interfaces'))
|
||||
sim = selected(properties('org.ofono.SimManager'), ('Present', 'PinRequired', 'LockedPins'))
|
||||
registration = selected(properties('org.ofono.NetworkRegistration'), ('Status', 'Technology', 'Strength'))
|
||||
interfaces = modem.get('Interfaces') or []
|
||||
report['telephony'] = {'modem': modem, 'sim': sim, 'registration': registration,
|
||||
'voiceInterface': 'org.ofono.VoiceCallManager' in interfaces,
|
||||
'smsInterface': 'org.ofono.MessageManager' in interfaces,
|
||||
'outgoingOperationsPerformed': False}
|
||||
report['audio'] = {}
|
||||
# Run as the session user for access to their PulseAudio server.
|
||||
for kind in ('sinks', 'sources'):
|
||||
raw = command(['pactl', '--format=json', 'list', kind])
|
||||
try:
|
||||
items = json.loads(raw) if raw else None
|
||||
if items is None:
|
||||
short = command(['pactl', 'list', 'short', kind])
|
||||
items = [] if short is not None else None
|
||||
for line in (short or '').splitlines():
|
||||
fields = line.split('\t')
|
||||
if len(fields) >= 5:
|
||||
items.append({'name': fields[1], 'state': fields[-1],
|
||||
'driver': fields[2]})
|
||||
if items is None:
|
||||
report['audio'][kind] = None
|
||||
continue
|
||||
report['audio'][kind] = [{key: item.get(key) for key in
|
||||
('name', 'state', 'mute', 'active_port', 'driver')}
|
||||
for item in items]
|
||||
except (TypeError, ValueError):
|
||||
report['audio'][kind] = []
|
||||
report['camera'] = {
|
||||
'halProbeOnly': True,
|
||||
'applicationInstalled': Path('/usr/bin/droidian-camera').exists(),
|
||||
'captureTested': False,
|
||||
}
|
||||
report['battery'] = {}
|
||||
for name in ('capacity', 'status'):
|
||||
try:
|
||||
report['battery'][name] = Path('/sys/class/power_supply/battery', name).read_text().strip()
|
||||
except OSError:
|
||||
pass
|
||||
return report
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(json.dumps(inspect(), indent=2))
|
||||
Loading…
Reference in a new issue