swarmit 0.3.0__py3-none-any.whl → 0.4.4__py3-none-any.whl
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.
- swarmit-0.4.4.dist-info/METADATA +127 -0
- swarmit-0.4.4.dist-info/RECORD +12 -0
- testbed/cli/main.py +140 -170
- testbed/swarmit/__init__.py +1 -1
- testbed/swarmit/adapter.py +112 -64
- testbed/swarmit/controller.py +350 -306
- testbed/swarmit/protocol.py +38 -99
- swarmit-0.3.0.dist-info/METADATA +0 -101
- swarmit-0.3.0.dist-info/RECORD +0 -12
- {swarmit-0.3.0.dist-info → swarmit-0.4.4.dist-info}/WHEEL +0 -0
- {swarmit-0.3.0.dist-info → swarmit-0.4.4.dist-info}/entry_points.txt +0 -0
- {swarmit-0.3.0.dist-info → swarmit-0.4.4.dist-info}/licenses/AUTHORS +0 -0
- {swarmit-0.3.0.dist-info → swarmit-0.4.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,127 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: swarmit
|
3
|
+
Version: 0.4.4
|
4
|
+
Summary: Run Your Own Robot Swarm Testbed.
|
5
|
+
Project-URL: Homepage, https://github.com/DotBots/swarmit
|
6
|
+
Project-URL: Bug Tracker, https://github.com/DotBots/swarmit/issues
|
7
|
+
Author-email: Alexandre Abadie <alexandre.abadie@inria.fr>
|
8
|
+
License: BSD
|
9
|
+
License-File: AUTHORS
|
10
|
+
License-File: LICENSE
|
11
|
+
Classifier: License :: OSI Approved :: BSD License
|
12
|
+
Classifier: Operating System :: MacOS
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
16
|
+
Requires-Python: >=3.7
|
17
|
+
Requires-Dist: click==8.1.7
|
18
|
+
Requires-Dist: cryptography==43.0.1
|
19
|
+
Requires-Dist: marilib-pkg>=0.6.0
|
20
|
+
Requires-Dist: pydotbot>=0.24.1
|
21
|
+
Requires-Dist: rich==14.0.0
|
22
|
+
Requires-Dist: structlog==24.4.0
|
23
|
+
Requires-Dist: tqdm==4.66.5
|
24
|
+
Description-Content-Type: text/markdown
|
25
|
+
|
26
|
+
# SwarmIT
|
27
|
+
|
28
|
+
SwarmIT provides a embedded C port for nRF53 as well as Python based services to
|
29
|
+
easily build and deploy a robotic swarm infrastructure testbed.
|
30
|
+
ARM TrustZone is used to create a sandboxed user environment on each device
|
31
|
+
under test, without requiring a control co-processor attached to it.
|
32
|
+
|
33
|
+
https://github.com/user-attachments/assets/eff63b07-216a-41fb-9062-2e0e56f03c20
|
34
|
+
|
35
|
+
## Features
|
36
|
+
|
37
|
+
- Experiment management: start, stop, monitor and status check
|
38
|
+
- Deploy a custom firmware on all or on a subset of robots of a swarm testbed
|
39
|
+
- Resilient robot state: even when crashed by buggy user code, the robot can be reprogrammed remotely and wirelessly
|
40
|
+
|
41
|
+
## Usage
|
42
|
+
|
43
|
+
### Get the code
|
44
|
+
|
45
|
+
Swarmit depends on the [DotBot-firmware](https://github.com/DotBots/DotBot-firmware)
|
46
|
+
and [Mari](https://github.com/DotBots/mari) repositories. They are included
|
47
|
+
in the codebase as [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules).
|
48
|
+
|
49
|
+
Use the following command to clone the Swarmit codebase locally:
|
50
|
+
|
51
|
+
```
|
52
|
+
git clone --recurse-submodules https://github.com/DotBots/swarmit.git
|
53
|
+
```
|
54
|
+
|
55
|
+
### Embedded C code
|
56
|
+
|
57
|
+
SwarmIT embedded C code can be built using
|
58
|
+
[Segger Embedded Studio (SES)](https://www.segger.com/products/development-tools/embedded-studio/).
|
59
|
+
Use Tools > Package manager to install the CMSIS 5 CMSIS-CORE, CMSIS-DSP and nRF packages.
|
60
|
+
|
61
|
+
To provision a device, follow the following steps:
|
62
|
+
1. open [netcore.emProject](swarmit-netcore.emProject)
|
63
|
+
and [bootloader.emProject](swarmit-bootloader-dotbot-v3.emProject)
|
64
|
+
(or [bootloader.emProject](swarmit-bootloader-dotbot-v2.emProject) depending on
|
65
|
+
your robot version) in SES
|
66
|
+
2. build and load the netcore application on the nRF53 network core,
|
67
|
+
3. build and load the bootloader application on the nRF53 application core.
|
68
|
+
|
69
|
+
The device is now ready.
|
70
|
+
|
71
|
+
### Gateway
|
72
|
+
|
73
|
+
The communication between the computer and the swarm devices is performed via a
|
74
|
+
gateway board connected via USB to the computer.
|
75
|
+
|
76
|
+
This gateway uses the [mari](https://github.com/dotbots/mari) network stack and
|
77
|
+
the it must run the Mari gateway firmware, either Edge or Cloud version.
|
78
|
+
|
79
|
+
The documentation to setup a Mari gateway is located
|
80
|
+
[here](https://github.com/DotBots/mari/wiki/Getting-started#running-mari-network-on-your-computer).
|
81
|
+
|
82
|
+
### Python CLI script
|
83
|
+
|
84
|
+
The Python CLI script provides commands for flashing, starting and stopping user
|
85
|
+
code on the device, as well as monitoring and checking the status of devices
|
86
|
+
in the swarm.
|
87
|
+
|
88
|
+
The Python CLI script connects via a virtual COM port to the gateway connected to
|
89
|
+
the computer.
|
90
|
+
|
91
|
+
The Python CLI script is available on PyPI. Install it using:
|
92
|
+
|
93
|
+
```
|
94
|
+
pip install swarmit
|
95
|
+
```
|
96
|
+
|
97
|
+
Print usage using `swarmit --help`:
|
98
|
+
|
99
|
+
```
|
100
|
+
Usage: swarmit [OPTIONS] COMMAND [ARGS]...
|
101
|
+
|
102
|
+
Options:
|
103
|
+
-p, --port TEXT Serial port to use to send the bitstream to
|
104
|
+
the gateway. Default: /dev/ttyACM0.
|
105
|
+
-b, --baudrate INTEGER Serial port baudrate. Default: 1000000.
|
106
|
+
-H, --mqtt-host TEXT MQTT host. Default: localhost.
|
107
|
+
-P, --mqtt-port INTEGER MQTT port. Default: 1883.
|
108
|
+
-T, --mqtt-use_tls Use TLS with MQTT.
|
109
|
+
-n, --network-id INTEGER Marilib network ID to use. Default: 1
|
110
|
+
-a, --adapter [edge|cloud]
|
111
|
+
Choose the adapter to communicate with the
|
112
|
+
gateway. [default: edge]
|
113
|
+
-d, --devices TEXT Subset list of devices to interact with,
|
114
|
+
separated with ,
|
115
|
+
-v, --verbose Enable verbose mode.
|
116
|
+
-V, --version Show the version and exit.
|
117
|
+
-h, --help Show this message and exit.
|
118
|
+
|
119
|
+
Commands:
|
120
|
+
flash Flash a firmware to the robots.
|
121
|
+
message Send a custom text message to the robots.
|
122
|
+
monitor Monitor running applications.
|
123
|
+
reset Reset robots locations.
|
124
|
+
start Start the user application.
|
125
|
+
status Print current status of the robots.
|
126
|
+
stop Stop the user application.
|
127
|
+
```
|
@@ -0,0 +1,12 @@
|
|
1
|
+
dotbot-firmware/doc/sphinx/conf.py,sha256=uQJVglqE9HoqMXJf5nbmCVCLSSGbqfiSr5ZQbE7HsLk,6211
|
2
|
+
testbed/cli/main.py,sha256=2jix2xPzP4XLcnpk804gKGOJWnXAho73lbZXqJGk_6g,9399
|
3
|
+
testbed/swarmit/__init__.py,sha256=6G_giX6Ucuweo7w5OiftoXmbNLoqiU_soXJoU8aiLmY,22
|
4
|
+
testbed/swarmit/adapter.py,sha256=Qmx7ULkx0OfyU7PJh-VBQibEOhvnDfnB3_DmntQ2tfU,4616
|
5
|
+
testbed/swarmit/controller.py,sha256=7XTX0Px8hnzE-ebUsMLFuPs3uKOrdBSle2mkOuW_gVQ,22354
|
6
|
+
testbed/swarmit/protocol.py,sha256=tkPMIGo_G1Fvo3zM6_zk4a3i3gqLtEzDFf97VRHa4B4,6344
|
7
|
+
swarmit-0.4.4.dist-info/METADATA,sha256=tsOWOAwVvJNzJxJleyTLcTcaaqFjuYgmSVaEr2A10xE,4837
|
8
|
+
swarmit-0.4.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
9
|
+
swarmit-0.4.4.dist-info/entry_points.txt,sha256=R6BGQe6I1FcI5B2jo7Dr-Gh6-Rjn1Ykx3uAGuV5rVTo,50
|
10
|
+
swarmit-0.4.4.dist-info/licenses/AUTHORS,sha256=o2cH3J5JkbZssK_1zYj0m8PHiGiILV0lySR6_hoWKK0,45
|
11
|
+
swarmit-0.4.4.dist-info/licenses/LICENSE,sha256=j97C1uBc5chpQWi4bv_2SrqExuvKaJK2Ch6L2LFkoc4,1492
|
12
|
+
swarmit-0.4.4.dist-info/RECORD,,
|
testbed/cli/main.py
CHANGED
@@ -14,49 +14,100 @@ from rich.pretty import pprint
|
|
14
14
|
from testbed.swarmit import __version__
|
15
15
|
from testbed.swarmit.controller import (
|
16
16
|
CHUNK_SIZE,
|
17
|
+
OTA_ACK_TIMEOUT_DEFAULT,
|
18
|
+
OTA_MAX_RETRIES_DEFAULT,
|
17
19
|
Controller,
|
18
20
|
ControllerSettings,
|
19
21
|
ResetLocation,
|
20
|
-
print_start_status,
|
21
|
-
print_status,
|
22
|
-
print_stop_status,
|
23
22
|
print_transfer_status,
|
24
23
|
)
|
25
24
|
|
26
25
|
SERIAL_PORT_DEFAULT = get_default_port()
|
27
26
|
BAUDRATE_DEFAULT = 1000000
|
27
|
+
MQTT_HOST_DEFAULT = "localhost"
|
28
|
+
MQTT_PORT_DEFAULT = 1883
|
29
|
+
# Default network ID for SwarmIT tests is 0x12**
|
30
|
+
# See https://crystalfree.atlassian.net/wiki/spaces/Mari/pages/3324903426/Registry+of+Mari+Network+IDs
|
31
|
+
SWARMIT_NETWORK_ID_DEFAULT = "1200"
|
28
32
|
|
29
33
|
|
30
34
|
@click.group(context_settings=dict(help_option_names=["-h", "--help"]))
|
31
|
-
@click.version_option(version=__version__)
|
32
35
|
@click.option(
|
33
36
|
"-p",
|
34
37
|
"--port",
|
38
|
+
type=str,
|
35
39
|
default=SERIAL_PORT_DEFAULT,
|
36
40
|
help=f"Serial port to use to send the bitstream to the gateway. Default: {SERIAL_PORT_DEFAULT}.",
|
37
41
|
)
|
38
42
|
@click.option(
|
39
43
|
"-b",
|
40
44
|
"--baudrate",
|
45
|
+
type=int,
|
41
46
|
default=BAUDRATE_DEFAULT,
|
42
47
|
help=f"Serial port baudrate. Default: {BAUDRATE_DEFAULT}.",
|
43
48
|
)
|
44
49
|
@click.option(
|
45
|
-
"-
|
46
|
-
"--
|
50
|
+
"-H",
|
51
|
+
"--mqtt-host",
|
52
|
+
type=str,
|
53
|
+
default=MQTT_HOST_DEFAULT,
|
54
|
+
help=f"MQTT host. Default: {MQTT_HOST_DEFAULT}.",
|
55
|
+
)
|
56
|
+
@click.option(
|
57
|
+
"-P",
|
58
|
+
"--mqtt-port",
|
59
|
+
type=int,
|
60
|
+
default=MQTT_PORT_DEFAULT,
|
61
|
+
help=f"MQTT port. Default: {MQTT_PORT_DEFAULT}.",
|
62
|
+
)
|
63
|
+
@click.option(
|
64
|
+
"-T",
|
65
|
+
"--mqtt-use_tls",
|
47
66
|
is_flag=True,
|
48
|
-
|
49
|
-
|
67
|
+
help="Use TLS with MQTT.",
|
68
|
+
)
|
69
|
+
@click.option(
|
70
|
+
"-n",
|
71
|
+
"--network-id",
|
72
|
+
type=str,
|
73
|
+
default=SWARMIT_NETWORK_ID_DEFAULT,
|
74
|
+
help=f"Marilib network ID to use. Default: 0x{SWARMIT_NETWORK_ID_DEFAULT}",
|
75
|
+
)
|
76
|
+
@click.option(
|
77
|
+
"-a",
|
78
|
+
"--adapter",
|
79
|
+
type=click.Choice(["edge", "cloud"], case_sensitive=True),
|
80
|
+
default="edge",
|
81
|
+
show_default=True,
|
82
|
+
help="Choose the adapter to communicate with the gateway.",
|
50
83
|
)
|
51
84
|
@click.option(
|
52
85
|
"-d",
|
53
86
|
"--devices",
|
54
87
|
type=str,
|
55
88
|
default="",
|
56
|
-
help="Subset list of
|
89
|
+
help="Subset list of device addresses to interact with, separated with ,",
|
57
90
|
)
|
91
|
+
@click.option(
|
92
|
+
"-v",
|
93
|
+
"--verbose",
|
94
|
+
is_flag=True,
|
95
|
+
help="Enable verbose mode.",
|
96
|
+
)
|
97
|
+
@click.version_option(__version__, "-V", "--version", prog_name="swarmit")
|
58
98
|
@click.pass_context
|
59
|
-
def main(
|
99
|
+
def main(
|
100
|
+
ctx,
|
101
|
+
port,
|
102
|
+
baudrate,
|
103
|
+
mqtt_host,
|
104
|
+
mqtt_port,
|
105
|
+
mqtt_use_tls,
|
106
|
+
network_id,
|
107
|
+
adapter,
|
108
|
+
devices,
|
109
|
+
verbose,
|
110
|
+
):
|
60
111
|
if ctx.invoked_subcommand != "monitor":
|
61
112
|
# Disable logging if not monitoring
|
62
113
|
structlog.configure(
|
@@ -65,32 +116,25 @@ def main(ctx, port, baudrate, edge, devices):
|
|
65
116
|
),
|
66
117
|
)
|
67
118
|
ctx.ensure_object(dict)
|
68
|
-
ctx.obj["
|
69
|
-
|
70
|
-
|
71
|
-
|
119
|
+
ctx.obj["settings"] = ControllerSettings(
|
120
|
+
serial_port=port,
|
121
|
+
serial_baudrate=baudrate,
|
122
|
+
mqtt_host=mqtt_host,
|
123
|
+
mqtt_port=mqtt_port,
|
124
|
+
mqtt_use_tls=mqtt_use_tls,
|
125
|
+
network_id=int(network_id, 16),
|
126
|
+
adapter=adapter,
|
127
|
+
devices=[d for d in devices.split(",") if d],
|
128
|
+
verbose=verbose,
|
129
|
+
)
|
72
130
|
|
73
131
|
|
74
132
|
@main.command()
|
75
|
-
@click.option(
|
76
|
-
"-v",
|
77
|
-
"--verbose",
|
78
|
-
is_flag=True,
|
79
|
-
help="Print start result.",
|
80
|
-
)
|
81
133
|
@click.pass_context
|
82
|
-
def start(ctx
|
134
|
+
def start(ctx):
|
83
135
|
"""Start the user application."""
|
84
136
|
try:
|
85
|
-
|
86
|
-
serial_port=ctx.obj["port"],
|
87
|
-
serial_baudrate=ctx.obj["baudrate"],
|
88
|
-
mqtt_host="argus.paris.inria.fr",
|
89
|
-
mqtt_port=8883,
|
90
|
-
edge=ctx.obj["edge"],
|
91
|
-
devices=list(ctx.obj["devices"]),
|
92
|
-
)
|
93
|
-
controller = Controller(settings)
|
137
|
+
controller = Controller(ctx.obj["settings"])
|
94
138
|
except (
|
95
139
|
SerialInterfaceException,
|
96
140
|
serial.serialutil.SerialException,
|
@@ -99,43 +143,18 @@ def start(ctx, verbose):
|
|
99
143
|
console.print(f"[bold red]Error:[/] {exc}")
|
100
144
|
return
|
101
145
|
if controller.ready_devices:
|
102
|
-
|
103
|
-
print_start_status(
|
104
|
-
sorted(started),
|
105
|
-
sorted(set(controller.ready_devices).difference(set(started))),
|
106
|
-
)
|
107
|
-
if verbose:
|
108
|
-
print("Started devices:")
|
109
|
-
pprint(started)
|
110
|
-
print("Not started devices:")
|
111
|
-
pprint(
|
112
|
-
sorted(set(controller.ready_devices).difference(set(started)))
|
113
|
-
)
|
146
|
+
controller.start()
|
114
147
|
else:
|
115
148
|
print("No device to start")
|
116
149
|
controller.terminate()
|
117
150
|
|
118
151
|
|
119
152
|
@main.command()
|
120
|
-
@click.option(
|
121
|
-
"-v",
|
122
|
-
"--verbose",
|
123
|
-
is_flag=True,
|
124
|
-
help="Print start result.",
|
125
|
-
)
|
126
153
|
@click.pass_context
|
127
|
-
def stop(ctx
|
154
|
+
def stop(ctx):
|
128
155
|
"""Stop the user application."""
|
129
156
|
try:
|
130
|
-
|
131
|
-
serial_port=ctx.obj["port"],
|
132
|
-
serial_baudrate=ctx.obj["baudrate"],
|
133
|
-
mqtt_host="argus.paris.inria.fr",
|
134
|
-
mqtt_port=8883,
|
135
|
-
edge=ctx.obj["edge"],
|
136
|
-
devices=list(ctx.obj["devices"]),
|
137
|
-
)
|
138
|
-
controller = Controller(settings)
|
157
|
+
controller = Controller(ctx.obj["settings"])
|
139
158
|
except (
|
140
159
|
SerialInterfaceException,
|
141
160
|
serial.serialutil.SerialException,
|
@@ -144,29 +163,9 @@ def stop(ctx, verbose):
|
|
144
163
|
console.print(f"[bold red]Error:[/] {exc}")
|
145
164
|
return
|
146
165
|
if controller.running_devices or controller.resetting_devices:
|
147
|
-
|
148
|
-
print_stop_status(
|
149
|
-
sorted(stopped),
|
150
|
-
sorted(
|
151
|
-
set(
|
152
|
-
controller.running_devices + controller.resetting_devices
|
153
|
-
).difference(set(stopped))
|
154
|
-
),
|
155
|
-
)
|
156
|
-
if verbose:
|
157
|
-
print("Started devices:")
|
158
|
-
pprint(stopped)
|
159
|
-
print("Not started devices:")
|
160
|
-
pprint(
|
161
|
-
sorted(
|
162
|
-
set(
|
163
|
-
controller.running_devices
|
164
|
-
+ controller.resetting_devices
|
165
|
-
).difference(set(stopped))
|
166
|
-
)
|
167
|
-
)
|
166
|
+
controller.stop()
|
168
167
|
else:
|
169
|
-
print("No device to stop")
|
168
|
+
print("[bold]No device to stop[/]")
|
170
169
|
controller.terminate()
|
171
170
|
|
172
171
|
|
@@ -179,39 +178,32 @@ def stop(ctx, verbose):
|
|
179
178
|
def reset(ctx, locations):
|
180
179
|
"""Reset robots locations.
|
181
180
|
|
182
|
-
Locations are provided as '<
|
181
|
+
Locations are provided as '<device_addr>:<x>,<y>-<device_addr>:<x>,<y>|...'
|
183
182
|
"""
|
184
|
-
|
183
|
+
try:
|
184
|
+
controller = Controller(ctx.obj["settings"])
|
185
|
+
except (
|
186
|
+
SerialInterfaceException,
|
187
|
+
serial.serialutil.SerialException,
|
188
|
+
) as exc:
|
189
|
+
console = Console()
|
190
|
+
console.print(f"[bold red]Error:[/] {exc}")
|
191
|
+
return
|
192
|
+
|
193
|
+
devices = controller.settings.devices
|
185
194
|
if not devices:
|
186
195
|
print("No devices selected.")
|
187
196
|
return
|
188
197
|
locations = {
|
189
|
-
location.split(
|
190
|
-
pos_x=int(float(location.split(
|
191
|
-
pos_y=int(float(location.split(
|
198
|
+
int(location.split(":")[0], 16): ResetLocation(
|
199
|
+
pos_x=int(float(location.split(":")[1].split(",")[0]) * 1e6),
|
200
|
+
pos_y=int(float(location.split(":")[1].split(",")[1]) * 1e6),
|
192
201
|
)
|
193
202
|
for location in locations.split("-")
|
194
203
|
}
|
195
204
|
if sorted(devices) and sorted(locations.keys()) != sorted(devices):
|
196
205
|
print("Selected devices and reset locations do not match.")
|
197
206
|
return
|
198
|
-
try:
|
199
|
-
settings = ControllerSettings(
|
200
|
-
serial_port=ctx.obj["port"],
|
201
|
-
serial_baudrate=ctx.obj["baudrate"],
|
202
|
-
mqtt_host="argus.paris.inria.fr",
|
203
|
-
mqtt_port=8883,
|
204
|
-
edge=ctx.obj["edge"],
|
205
|
-
devices=list(ctx.obj["devices"]),
|
206
|
-
)
|
207
|
-
controller = Controller(settings)
|
208
|
-
except (
|
209
|
-
SerialInterfaceException,
|
210
|
-
serial.serialutil.SerialException,
|
211
|
-
) as exc:
|
212
|
-
console = Console()
|
213
|
-
console.print(f"[bold red]Error:[/] {exc}")
|
214
|
-
return
|
215
207
|
if not controller.ready_devices:
|
216
208
|
print("No device to reset.")
|
217
209
|
return
|
@@ -233,32 +225,35 @@ def reset(ctx, locations):
|
|
233
225
|
help="Start the firmware once flashed.",
|
234
226
|
)
|
235
227
|
@click.option(
|
236
|
-
"-
|
237
|
-
"--
|
238
|
-
|
239
|
-
|
228
|
+
"-t",
|
229
|
+
"--ota-timeout",
|
230
|
+
type=float,
|
231
|
+
default=OTA_ACK_TIMEOUT_DEFAULT,
|
232
|
+
show_default=True,
|
233
|
+
help="Timeout in seconds for each OTA ACK message.",
|
234
|
+
)
|
235
|
+
@click.option(
|
236
|
+
"-r",
|
237
|
+
"--ota-max-retries",
|
238
|
+
type=int,
|
239
|
+
default=OTA_MAX_RETRIES_DEFAULT,
|
240
|
+
show_default=True,
|
241
|
+
help="Number of retries for each OTA message (start or chunk) transfer.",
|
240
242
|
)
|
241
243
|
@click.argument("firmware", type=click.File(mode="rb"), required=False)
|
242
244
|
@click.pass_context
|
243
|
-
def flash(ctx, yes, start,
|
245
|
+
def flash(ctx, yes, start, ota_timeout, ota_max_retries, firmware):
|
244
246
|
"""Flash a firmware to the robots."""
|
245
247
|
console = Console()
|
246
248
|
if firmware is None:
|
247
249
|
console.print("[bold red]Error:[/] Missing firmware file. Exiting.")
|
248
250
|
ctx.exit()
|
249
|
-
|
251
|
+
ctx.obj["settings"].ota_timeout = ota_timeout
|
252
|
+
ctx.obj["settings"].ota_max_retries = ota_max_retries
|
250
253
|
fw = bytearray(firmware.read())
|
251
|
-
|
252
|
-
serial_port=ctx.obj["port"],
|
253
|
-
serial_baudrate=ctx.obj["baudrate"],
|
254
|
-
mqtt_host="argus.paris.inria.fr",
|
255
|
-
mqtt_port=8883,
|
256
|
-
edge=ctx.obj["edge"],
|
257
|
-
devices=ctx.obj["devices"],
|
258
|
-
)
|
259
|
-
controller = Controller(settings)
|
254
|
+
controller = Controller(ctx.obj["settings"])
|
260
255
|
if not controller.ready_devices:
|
261
|
-
console.print("[bold red]Error:[/] No ready
|
256
|
+
console.print("[bold red]Error:[/] No ready device found. Exiting.")
|
262
257
|
controller.terminate()
|
263
258
|
return
|
264
259
|
print(
|
@@ -268,41 +263,44 @@ def flash(ctx, yes, start, verbose, firmware):
|
|
268
263
|
if yes is False:
|
269
264
|
click.confirm("Do you want to continue?", default=True, abort=True)
|
270
265
|
|
271
|
-
devices = controller.settings.devices
|
272
266
|
start_data = controller.start_ota(fw)
|
273
|
-
if
|
274
|
-
|
275
|
-
|
276
|
-
|
267
|
+
if controller.settings.verbose:
|
268
|
+
print("\n[b]Start OTA response:[/]")
|
269
|
+
pprint(start_data, indent_guides=False, expand_all=True)
|
270
|
+
if start_data["missed"]:
|
277
271
|
console = Console()
|
278
272
|
console.print(
|
279
|
-
"[bold red]Error:[/]
|
280
|
-
f
|
273
|
+
f"[bold red]Error:[/] {len(start_data["missed"])} acknowledgments "
|
274
|
+
f"are missing ({', '.join(sorted(set(start_data["missed"])))}). "
|
281
275
|
"Aborting."
|
282
276
|
)
|
277
|
+
controller.stop()
|
278
|
+
controller.terminate()
|
283
279
|
raise click.Abort()
|
284
280
|
print()
|
285
281
|
print(f"Image size: [bold cyan]{len(fw)}B[/]")
|
286
|
-
print(
|
287
|
-
|
282
|
+
print(
|
283
|
+
f"Image hash: [bold cyan]{start_data["ota"].fw_hash.hex().upper()}[/]"
|
284
|
+
)
|
285
|
+
print(
|
286
|
+
f"Radio chunks ([bold]{CHUNK_SIZE}B[/bold]): {start_data["ota"].chunks}"
|
287
|
+
)
|
288
288
|
start_time = time.time()
|
289
|
-
data = controller.transfer(fw)
|
289
|
+
data = controller.transfer(fw, start_data["acked"])
|
290
290
|
print(f"Elapsed: [bold cyan]{time.time() - start_time:.3f}s[/bold cyan]")
|
291
|
-
print_transfer_status(data, start_data)
|
292
|
-
if verbose:
|
293
|
-
|
294
|
-
|
291
|
+
print_transfer_status(data, start_data["ota"])
|
292
|
+
if controller.settings.verbose:
|
293
|
+
print("\n[b]Transfer data:[/]")
|
294
|
+
pprint(data, indent_guides=False, expand_all=True)
|
295
|
+
if all([device.success for device in data.values()]) is False:
|
295
296
|
controller.terminate()
|
296
297
|
console = Console()
|
297
|
-
console.print("[bold red]Error:[/]
|
298
|
+
console.print("[bold red]Error:[/] Transfer failed.")
|
298
299
|
raise click.Abort()
|
299
300
|
|
300
301
|
if start is True:
|
301
|
-
|
302
|
-
|
303
|
-
sorted(started),
|
304
|
-
sorted(set(start_data.ids).difference(set(started))),
|
305
|
-
)
|
302
|
+
time.sleep(1)
|
303
|
+
controller.start()
|
306
304
|
controller.terminate()
|
307
305
|
|
308
306
|
|
@@ -311,15 +309,7 @@ def flash(ctx, yes, start, verbose, firmware):
|
|
311
309
|
def monitor(ctx):
|
312
310
|
"""Monitor running applications."""
|
313
311
|
try:
|
314
|
-
|
315
|
-
serial_port=ctx.obj["port"],
|
316
|
-
serial_baudrate=ctx.obj["baudrate"],
|
317
|
-
mqtt_host="argus.paris.inria.fr",
|
318
|
-
mqtt_port=8883,
|
319
|
-
edge=ctx.obj["edge"],
|
320
|
-
devices=ctx.obj["devices"],
|
321
|
-
)
|
322
|
-
controller = Controller(settings)
|
312
|
+
controller = Controller(ctx.obj["settings"])
|
323
313
|
except (
|
324
314
|
SerialInterfaceException,
|
325
315
|
serial.serialutil.SerialException,
|
@@ -339,20 +329,8 @@ def monitor(ctx):
|
|
339
329
|
@click.pass_context
|
340
330
|
def status(ctx):
|
341
331
|
"""Print current status of the robots."""
|
342
|
-
|
343
|
-
|
344
|
-
serial_baudrate=ctx.obj["baudrate"],
|
345
|
-
mqtt_host="argus.paris.inria.fr",
|
346
|
-
mqtt_port=8883,
|
347
|
-
edge=ctx.obj["edge"],
|
348
|
-
devices=ctx.obj["devices"],
|
349
|
-
)
|
350
|
-
controller = Controller(settings)
|
351
|
-
data = controller.status()
|
352
|
-
if not data:
|
353
|
-
click.echo("No devices found.")
|
354
|
-
else:
|
355
|
-
print_status(data)
|
332
|
+
controller = Controller(ctx.obj["settings"])
|
333
|
+
controller.status()
|
356
334
|
controller.terminate()
|
357
335
|
|
358
336
|
|
@@ -361,15 +339,7 @@ def status(ctx):
|
|
361
339
|
@click.pass_context
|
362
340
|
def message(ctx, message):
|
363
341
|
"""Send a custom text message to the robots."""
|
364
|
-
|
365
|
-
serial_port=ctx.obj["port"],
|
366
|
-
serial_baudrate=ctx.obj["baudrate"],
|
367
|
-
mqtt_host="argus.paris.inria.fr",
|
368
|
-
mqtt_port=8883,
|
369
|
-
edge=ctx.obj["edge"],
|
370
|
-
devices=ctx.obj["devices"],
|
371
|
-
)
|
372
|
-
controller = Controller(settings)
|
342
|
+
controller = Controller(ctx.obj["settings"])
|
373
343
|
controller.send_message(message)
|
374
344
|
controller.terminate()
|
375
345
|
|
testbed/swarmit/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.
|
1
|
+
__version__ = "0.4.4"
|