Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/infuse_iot/generated/kv_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,19 @@ class bluetooth_peer(VLACompatLittleEndianStruct):
]
_pack_ = 1

class gravity_reference(VLACompatLittleEndianStruct):
"""Reference gravity vector for tilt calculations"""

NAME = "GRAVITY_REFERENCE"
BASE_ID = 60
RANGE = 1
_fields_ = [
("x", ctypes.c_int16),
("y", ctypes.c_int16),
("z", ctypes.c_int16),
]
_pack_ = 1

class geofence(VLACompatLittleEndianStruct):
"""Array of points defining a closed polygon"""

Expand Down Expand Up @@ -279,6 +292,7 @@ class secure_storage_reserved(VLACompatLittleEndianStruct):
44: lte_sim_uicc,
45: lte_pdp_config,
50: bluetooth_peer,
60: gravity_reference,
100: geofence,
101: geofence,
102: geofence,
Expand Down
34 changes: 34 additions & 0 deletions src/infuse_iot/generated/rpc_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,17 @@ class rpc_struct_wifi_scan_result(ctypes.LittleEndianStructure):
_pack_ = 1


class rpc_struct_xyz_s16(ctypes.LittleEndianStructure):
"""Signed 16 bit XYZ vector"""

_fields_ = [
("x", ctypes.c_int16),
("y", ctypes.c_int16),
("z", ctypes.c_int16),
]
_pack_ = 1


class rpc_enum_bt_le_addr_type(enum.IntEnum):
"""Bluetooth LE address type"""

Expand Down Expand Up @@ -616,6 +627,29 @@ class response(ctypes.LittleEndianStructure):
_pack_ = 1


class gravity_reference_update:
"""Store the current accelerometer vector as the gravity reference"""

HELP = "Store the current accelerometer vector as the gravity reference"
DESCRIPTION = "Store the current accelerometer vector as the gravity reference"
COMMAND_ID = 60

class request(ctypes.LittleEndianStructure):
_fields_ = [
("max_variance", ctypes.c_uint16),
]
_pack_ = 1

class response(ctypes.LittleEndianStructure):
_fields_ = [
("reference", rpc_struct_xyz_s16),
("variance", rpc_struct_xyz_s16),
("num_samples", ctypes.c_uint16),
("sample_period_us", ctypes.c_uint32),
]
_pack_ = 1


class security_state:
"""Query current security state and validate identity"""

Expand Down
16 changes: 15 additions & 1 deletion src/infuse_iot/generated/tdf_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def iter_fields(self, nested_iter: bool = True) -> Generator[TdfField, None, Non
for field in self._fields_:
f_name = _public_name(field)
val = getattr(self, f_name)
if nested_iter and isinstance(val, ctypes.LittleEndianStructure):
if nested_iter and isinstance(val, TdfStructBase):
yield from val.iter_fields(f_name)
else:
if isinstance(val, ctypes.Array):
Expand All @@ -78,6 +78,8 @@ def field_information(cls):
sf_name = _public_name(subfield)
subfields.append({"name": sf_name, "type": subfield[1]})
info.append({"name": f_name, "type": field[1], "subfields": subfields})
elif isinstance(field[1], ctypes.Array):
info.append({"name": f_name, "type": list})
else:
info.append({"name": f_name, "type": field[1]})
return info
Expand All @@ -103,14 +105,26 @@ def from_buffer_consume(cls, source: bytes, offset: int = 0) -> Self:
raise RuntimeError
source_var_num = source_var_len // var_type_size

# No trailing VLA
if source_var_num == 0:
return cls.from_buffer_copy(source, offset)

# Dynamically create subclass with correct length
class TdfVLA(ctypes.LittleEndianStructure):
name = cls.name
_fields_ = cls._fields_[:-1] + [(var_name, source_var_num * var_type)] # type: ignore
_pack_ = 1
_postfix_ = cls._postfix_
_display_fmt_ = cls._display_fmt_
_vla_field_ = var_name
iter_fields = cls.iter_fields
field_information = cls.field_information

# Copy convertor functions for fields
for f in cls._fields_:
if f[0][0] == "_":
f_name = f[0][1:]
setattr(TdfVLA, f_name, getattr(cls, f_name))

# Create the object instance
return cast(Self, TdfVLA.from_buffer_copy(source, offset))
122 changes: 122 additions & 0 deletions src/infuse_iot/generated/tdf_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,40 @@ class tdf_struct_lte_cell_id_global(TdfStructBase):
"tac": "{}",
}

class tdf_struct_lte_cell_neighbour(TdfStructBase):
"""LTE cell ID (Global)"""

_fields_ = [
("earfcn", ctypes.c_uint32),
("pci", ctypes.c_uint16),
("_time_diff", ctypes.c_uint16),
("_rsrp", ctypes.c_uint8),
("rsrq", ctypes.c_int8),
]
_pack_ = 1
_postfix_ = {
"earfcn": "",
"pci": "",
"time_diff": "s",
"rsrp": "dBm",
"rsrq": "dB",
}
_display_fmt_ = {
"earfcn": "{}",
"pci": "{}",
"time_diff": "{}",
"rsrp": "{}",
"rsrq": "{}",
}

@property
def time_diff(self):
return self._time_diff * 0.001

@property
def rsrp(self):
return self._rsrp * -1

class tdf_struct_bt_addr_le(TdfStructBase):
"""Bluetooth address type (bt_addr_le_t)"""

Expand All @@ -144,6 +178,24 @@ class tdf_struct_bt_addr_le(TdfStructBase):
def val(self):
return int.from_bytes(self._val, byteorder='little')

class tdf_struct_eui48(TdfStructBase):
"""IEEE EUI-48 address"""

_fields_ = [
("_val", 6 * ctypes.c_uint8),
]
_pack_ = 1
_postfix_ = {
"val": "",
}
_display_fmt_ = {
"val": "0x{:012x}",
}

@property
def val(self):
return int.from_bytes(self._val, byteorder='little')


class readings:
class announce(TdfReadingBase):
Expand Down Expand Up @@ -903,6 +955,73 @@ class algorithm_class_time_series(TdfReadingBase):
"values": "{}",
}

class lte_tac_cells(TdfReadingBase):
"""Information on cells in a tracking area"""

name = "LTE_TAC_CELLS"
_fields_ = [
("cell", structs.tdf_struct_lte_cell_id_global),
("earfcn", ctypes.c_uint32),
("_rsrp", ctypes.c_uint8),
("rsrq", ctypes.c_int8),
("neighbours", 0 * structs.tdf_struct_lte_cell_neighbour),
]
_pack_ = 1
_postfix_ = {
"cell": "",
"earfcn": "",
"rsrp": "dBm",
"rsrq": "dB",
"neighbours": "",
}
_display_fmt_ = {
"cell": "{}",
"earfcn": "{}",
"rsrp": "{}",
"rsrq": "{}",
"neighbours": "{}",
}

@property
def rsrp(self):
return self._rsrp * -1

class wifi_ap_info(TdfReadingBase):
"""Wi-Fi access point information"""

name = "WIFI_AP_INFO"
_fields_ = [
("bssid", structs.tdf_struct_eui48),
("channel", ctypes.c_uint8),
("rsrp", ctypes.c_int8),
]
_pack_ = 1
_postfix_ = {
"bssid": "",
"channel": "",
"rsrp": "",
}
_display_fmt_ = {
"bssid": "{}",
"channel": "{}",
"rsrp": "{}",
}

class device_tilt(TdfReadingBase):
"""Tilt angle of the device"""

name = "DEVICE_TILT"
_fields_ = [
("cosine", ctypes.c_float),
]
_pack_ = 1
_postfix_ = {
"cosine": "",
}
_display_fmt_ = {
"cosine": "{:.6f}",
}

class array_type(TdfReadingBase):
"""Example array type"""

Expand Down Expand Up @@ -950,5 +1069,8 @@ class array_type(TdfReadingBase):
31: readings.bluetooth_data_throughput,
32: readings.algorithm_class_histogram,
33: readings.algorithm_class_time_series,
34: readings.lte_tac_cells,
35: readings.wifi_ap_info,
36: readings.device_tilt,
100: readings.array_type,
}
37 changes: 37 additions & 0 deletions src/infuse_iot/rpc_wrappers/gravity_reference_update.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env python3

import errno
import os

import infuse_iot.generated.rpc_definitions as defs
from infuse_iot.commands import InfuseRpcCommand


class gravity_reference_update(InfuseRpcCommand, defs.gravity_reference_update):
@classmethod
def add_parser(cls, parser):
parser.add_argument("--variance", type=int, default=0, help="Maximum axis variance to accept")

def __init__(self, args):
self._max_variance = args.variance

def request_struct(self):
return self.request(self._max_variance)

def request_json(self):
return {"max_variance": str(self._max_variance)}

def handle_response(self, return_code, response):
r = response

if return_code == -errno.EIO:
print(f"IMU variance too large: {r.variance.x:6d} {r.variance.y:6d} {r.variance.z:6d}")
return
elif return_code < 0:
print(f"Failed to update gravity reference vector ({os.strerror(-return_code)})")
return

print(f"\t Gravity: {r.reference.x:6d} {r.reference.y:6d} {r.reference.z:6d}")
print(f"\t Variance: {r.variance.x:6d} {r.variance.y:6d} {r.variance.z:6d}")
print(f"\t Samples: {r.num_samples:d}")
print(f"\t Period: {r.sample_period_us:d} us")
46 changes: 35 additions & 11 deletions src/infuse_iot/tools/tdf_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from infuse_iot.commands import InfuseCommand
from infuse_iot.common import InfuseType
from infuse_iot.generated.tdf_base import TdfStructBase
from infuse_iot.socket_comms import (
ClientNotificationEpacketReceived,
LocalClient,
Expand Down Expand Up @@ -45,24 +46,47 @@ def run(self) -> None:
for tdf in self._decoder.decode(msg.epacket.payload):
t = tdf.data[-1]
num = len(tdf.data)
tdf_name: None | str = None
time_str: None | str = None
if num > 1:
tdf_name = f"{t.name}[{num - 1}]"
else:
tdf_name = t.name
if tdf.time is not None:
if tdf.period is None:
time_str = InfuseTime.utc_time_string(tdf.time)
else:
offset = (len(tdf.data) - 1) * tdf.period
time_str = InfuseTime.utc_time_string(tdf.time + offset)
else:
time_str = InfuseTime.utc_time_string(time.time())

for idx, field in enumerate(t.iter_fields()):
if idx == 0:
if tdf.time is not None:
if tdf.period is None:
time_str = InfuseTime.utc_time_string(tdf.time)
else:
offset = (len(tdf.data) - 1) * tdf.period
time_str = InfuseTime.utc_time_string(tdf.time + offset)
for field in t.iter_fields():
if isinstance(field.val, list):
# Trailing VLA handling
if len(field.val) > 0 and isinstance(field.val[0], TdfStructBase):
for idx, val in enumerate(field.val):
for subfield in val.iter_fields(f"{field.name}[{idx}]"):
table.append(
(
time_str,
tdf_name,
subfield.name,
subfield.val_fmt(),
subfield.postfix,
)
)
tdf_name = None
time_str = None
else:
time_str = InfuseTime.utc_time_string(time.time())
table.append((time_str, tdf_name, field.name, field.val_fmt(), field.postfix))
table.append((time_str, tdf_name, f"{field.name}", field.val_fmt(), field.postfix))
tdf_name = None
time_str = None
else:
table.append((None, None, field.name, field.val_fmt(), field.postfix))
# Standard structs and sub-structs
table.append((time_str, tdf_name, field.name, field.val_fmt(), field.postfix))
tdf_name = None
time_str = None

print(f"Infuse ID: {source.infuse_id:016x}")
print(f"Interface: {source.interface.name}")
Expand Down
Loading