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
22 changes: 22 additions & 0 deletions src/infuse_iot/generated/kv_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ class kv_algorithm_tilt_args(VLACompatLittleEndianStruct):
]
_pack_ = 1

class kv_algorithm_movement_threshold_args(VLACompatLittleEndianStruct):
"""Arguments for 'Shot Triggered' algorithm"""

_fields_ = [
("moving_for", ctypes.c_uint32),
("threshold_ug", ctypes.c_uint32),
]
_pack_ = 1


class slots:
class reboots(VLACompatLittleEndianStruct):
Expand Down Expand Up @@ -458,6 +467,18 @@ class alg_tilt_args(VLACompatLittleEndianStruct):
]
_pack_ = 1

class alg_movement_threshold_args(VLACompatLittleEndianStruct):
"""Configuration for the 'Movement Threshold' algorithm"""

NAME = "ALG_MOVEMENT_THRESHOLD_ARGS"
BASE_ID = 202
RANGE = 1
_fields_ = [
("logging", structs.kv_algorithm_logging),
("args", structs.kv_algorithm_movement_threshold_args),
]
_pack_ = 1

class task_schedules_default_id(VLACompatLittleEndianStruct):
"""Unique identifier for default schedule set"""

Expand Down Expand Up @@ -547,6 +568,7 @@ class secure_storage_reserved(VLACompatLittleEndianStruct):
115: geofence,
200: alg_stationary_windowed_args,
201: alg_tilt_args,
202: alg_movement_threshold_args,
1000: task_schedules_default_id,
1001: task_schedules,
1002: task_schedules,
Expand Down
87 changes: 87 additions & 0 deletions src/infuse_iot/generated/rpc_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,36 @@ class response(VLACompatLittleEndianStruct):
_pack_ = 1


class data_logger_state_v2(RPCDefinitionBase):
"""Get state of a data logger (Larger erase unit)"""

NAME = "data_logger_state_v2"
HELP = "Get state of a data logger (Larger erase unit)"
DESCRIPTION = "Get state of a data logger (Larger erase unit)"
COMMAND_ID = 24

class request(VLACompatLittleEndianStruct):
_fields_ = [
("logger", ctypes.c_uint8),
]
_pack_ = 1

class response(VLACompatLittleEndianStruct):
_fields_ = [
("bytes_logged", ctypes.c_uint64),
("logical_blocks", ctypes.c_uint32),
("physical_blocks", ctypes.c_uint32),
("boot_block", ctypes.c_uint32),
("current_block", ctypes.c_uint32),
("earliest_block", ctypes.c_uint32),
("block_size", ctypes.c_uint16),
("block_overhead", ctypes.c_uint16),
("erase_unit", ctypes.c_uint32),
("uptime", ctypes.c_uint32),
]
_pack_ = 1


class coap_download(RPCDefinitionBase):
"""Download a file from a COAP server (Infuse-IoT DTLS protected)"""

Expand Down Expand Up @@ -853,6 +883,35 @@ class response(VLACompatLittleEndianStruct):
_pack_ = 1


class coap_download_v2(RPCDefinitionBase):
"""Download a file from a COAP server (Infuse-IoT DTLS protected)"""

NAME = "coap_download_v2"
HELP = "Download a file from a COAP server (Infuse-IoT DTLS protected)"
DESCRIPTION = "Download a file from a COAP server (Infuse-IoT DTLS protected)"
COMMAND_ID = 32

class request(VLACompatLittleEndianStruct):
_fields_ = [
("server_address", 48 * ctypes.c_char),
("server_port", ctypes.c_uint16),
("block_timeout_ms", ctypes.c_uint16),
("block_size", ctypes.c_uint16),
("action", ctypes.c_uint8),
("resource_len", ctypes.c_uint32),
("resource_crc", ctypes.c_uint32),
]
vla_field = ("resource", 0 * ctypes.c_char)
_pack_ = 1

class response(VLACompatLittleEndianStruct):
_fields_ = [
("resource_len", ctypes.c_uint32),
("resource_crc", ctypes.c_uint32),
]
_pack_ = 1


class file_write_basic(RPCDefinitionBase):
"""Write a file to the device"""

Expand Down Expand Up @@ -1045,6 +1104,28 @@ class response(VLACompatLittleEndianStruct):
_pack_ = 1


class ubx_assist_now_ztp_creds(RPCDefinitionBase):
"""Retrieve U-blox AssistNow Zero Touch Provisioning credentials"""

NAME = "ubx_assist_now_ztp_creds"
HELP = "Retrieve U-blox AssistNow Zero Touch Provisioning credentials"
DESCRIPTION = "Retrieve U-blox AssistNow Zero Touch Provisioning credentials"
COMMAND_ID = 70

class request(VLACompatLittleEndianStruct):
_fields_ = [
("mon_ver_offset", ctypes.c_uint8),
]
_pack_ = 1

class response(VLACompatLittleEndianStruct):
_fields_ = [
("ubx_sec_uniqid", 18 * ctypes.c_uint8),
]
vla_field = ("ubx_mon_ver", 0 * ctypes.c_uint8)
_pack_ = 1


class security_state(RPCDefinitionBase):
"""Query current security state and validate identity"""

Expand Down Expand Up @@ -1175,8 +1256,10 @@ class response(VLACompatLittleEndianStruct):
lte_state.COMMAND_ID: lte_state,
data_logger_read_available.COMMAND_ID: data_logger_read_available,
lte_state_v2.COMMAND_ID: lte_state_v2,
data_logger_state_v2.COMMAND_ID: data_logger_state_v2,
coap_download.COMMAND_ID: coap_download,
zperf_upload.COMMAND_ID: zperf_upload,
coap_download_v2.COMMAND_ID: coap_download_v2,
file_write_basic.COMMAND_ID: file_write_basic,
annotate.COMMAND_ID: annotate,
bt_connect_infuse.COMMAND_ID: bt_connect_infuse,
Expand All @@ -1185,6 +1268,7 @@ class response(VLACompatLittleEndianStruct):
bt_file_copy_coap.COMMAND_ID: bt_file_copy_coap,
bt_mcumgr_reboot.COMMAND_ID: bt_mcumgr_reboot,
gravity_reference_update.COMMAND_ID: gravity_reference_update,
ubx_assist_now_ztp_creds.COMMAND_ID: ubx_assist_now_ztp_creds,
security_state.COMMAND_ID: security_state,
security_key_update.COMMAND_ID: security_key_update,
data_sender.COMMAND_ID: data_sender,
Expand Down Expand Up @@ -1240,8 +1324,10 @@ class response(VLACompatLittleEndianStruct):
"lte_state",
"data_logger_read_available",
"lte_state_v2",
"data_logger_state_v2",
"coap_download",
"zperf_upload",
"coap_download_v2",
"file_write_basic",
"annotate",
"bt_connect_infuse",
Expand All @@ -1250,6 +1336,7 @@ class response(VLACompatLittleEndianStruct):
"bt_file_copy_coap",
"bt_mcumgr_reboot",
"gravity_reference_update",
"ubx_assist_now_ztp_creds",
"security_state",
"security_key_update",
"data_sender",
Expand Down
2 changes: 1 addition & 1 deletion src/infuse_iot/rpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def _run_data_send_core(
rsp_decoder: Callable[[bytes], ctypes.LittleEndianStructure],
) -> tuple[rpc.ResponseHeader, ctypes.LittleEndianStructure | None]:
self._request_id += 1
ack_period = 1
ack_period = 2
header = rpc.RequestHeader(self._request_id, cmd_id) # type: ignore
data_hdr = rpc.RequestDataHeader(total_size, ack_period)

Expand Down
36 changes: 25 additions & 11 deletions src/infuse_iot/rpc_wrappers/wifi_configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,24 @@ def add_parser(cls, parser):
parser.add_argument(
"--channel", "-c", type=int, default=wifi.FrequencyChannel.CHANNEL_ANY, help="Network channel index"
)
parser.add_argument("--delete", action="store_true", help="Delete configured network")

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

def request_struct(self):
ssid_bytes = self.args.ssid.encode("utf-8") + b"\x00"
psk_bytes = self.args.psk.encode("utf-8") + b"\x00"
chan_bytes = self.args.band.to_bytes(1, "little") + self.args.channel.to_bytes(1, "little")
if self.args.delete:
ssid_struct = kv_write.kv_store_value_factory(20, b"")
psk_struct = kv_write.kv_store_value_factory(21, b"")
chan_struct = kv_write.kv_store_value_factory(22, b"")
else:
ssid_bytes = self.args.ssid.encode("utf-8") + b"\x00"
psk_bytes = self.args.psk.encode("utf-8") + b"\x00"
chan_bytes = self.args.band.to_bytes(1, "little") + self.args.channel.to_bytes(1, "little")

ssid_struct = kv_write.kv_store_value_factory(20, len(ssid_bytes).to_bytes(1, "little") + ssid_bytes)
psk_struct = kv_write.kv_store_value_factory(21, len(psk_bytes).to_bytes(1, "little") + psk_bytes)
chan_struct = kv_write.kv_store_value_factory(22, chan_bytes)
ssid_struct = kv_write.kv_store_value_factory(20, len(ssid_bytes).to_bytes(1, "little") + ssid_bytes)
psk_struct = kv_write.kv_store_value_factory(21, len(psk_bytes).to_bytes(1, "little") + psk_bytes)
chan_struct = kv_write.kv_store_value_factory(22, chan_bytes)

request_bytes = bytes(ssid_struct) + bytes(psk_struct) + bytes(chan_struct)
return bytes(self.request(3)) + request_bytes
Expand All @@ -82,12 +88,20 @@ def handle_response(self, return_code, response):
return

def print_status(name, rc):
if rc < 0:
print(f"{name} failed to write")
elif rc == 0:
print(f"{name} already matched")
if self.args.delete:
if rc == 0:
print(f"{name} deleted")
elif rc == -errno.ENOENT:
print(f"{name} did not exist")
else:
print(f"{name} failed to delete ({errno(-rc).name})")
else:
print(f"{name} updated")
if rc < 0:
print(f"{name} failed to write")
elif rc == 0:
print(f"{name} already matched")
else:
print(f"{name} updated")

print_status("SSID", response.rc[0])
print_status("PSK", response.rc[1])
Expand Down
22 changes: 17 additions & 5 deletions src/infuse_iot/tools/provision.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import ctypes
import sys
from http import HTTPStatus
from uuid import UUID

from infuse_iot.api_client import Client
from infuse_iot.api_client.api.board import get_board_by_id, get_boards
Expand All @@ -16,7 +17,7 @@
get_device_by_soc_and_mcu_id,
)
from infuse_iot.api_client.api.organisation import get_all_organisations
from infuse_iot.api_client.models import Board, DeviceMetadata, Error, NewDevice
from infuse_iot.api_client.models import Board, Device, DeviceMetadata, Error, NewDevice
from infuse_iot.commands import InfuseCommand
from infuse_iot.credentials import get_api_key
from infuse_iot.util.console import choose_one
Expand Down Expand Up @@ -66,8 +67,14 @@ def add_parser(cls, parser):
def __init__(self, args):
self._vendor = args.vendor
self._snr = args.snr
self._board = args.board
self._org = args.organisation
try:
self._board = UUID(args.board) if args.board else None
except ValueError:
sys.exit(f"Board ID: '{args.board}' is not a valid UUID")
try:
self._org = UUID(args.organisation) if args.organisation else None
except ValueError:
sys.exit(f"Organisation ID: '{args.organisation}' is not a valid UUID")
self._id = args.id
self._dry_run = args.dry_run
self._metadata = {}
Expand Down Expand Up @@ -138,6 +145,9 @@ def run(self):
)
if response.status_code == HTTPStatus.OK:
# Device found, fall through
assert isinstance(response.parsed, Device)
self._org = response.parsed.organisation_id
self._board = response.parsed.board_id
pass
elif response.status_code == HTTPStatus.NOT_FOUND:
# Create new device here
Expand All @@ -153,8 +163,6 @@ def run(self):
err = "Failed to query device after creation:\n"
err += f"\t<{response.status_code}> {response.content.decode('utf-8')}"
sys.exit(err)
print("To provision more devices like this:")
print(f"\t infuse provision --organisation {self._org} --board {self._board}")
else:
err = "Failed to query device information:\n"
err += f"\t<{response.status_code}> {response.content.decode('utf-8')}"
Expand All @@ -179,3 +187,7 @@ def run(self):
print(f"HW ID 0x{hardware_id:016x} now provisioned as 0x{desired.device_id:016x}")

interface.close()

example_cmd = f"infuse provision --organisation {self._org} --board {self._board} --{self._vendor}"
print("To provision more devices like this:")
print(f"\t {example_cmd}")