Skip to content

Commit 4a2e81d

Browse files
committed
tools/zep_dispatch: topogen: allow to pass worldfile
A world file might look like ``` A 5 3 10 B 10 C 20 20 ```
1 parent 1f6a7b4 commit 4a2e81d

File tree

2 files changed

+164
-5
lines changed

2 files changed

+164
-5
lines changed

dist/tools/zep_dispatch/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ This should also be visible in Foren6.
169169
Topology generation
170170
-------------------
171171

172+
#### Random Topology
173+
172174
To generate a random topology use the `topogen.sh` script.
173175
This will randomly distribute *N* nodes on on a *W* × *H* map.
174176
Each node has a radio range *R* ± *V* where *V* is a random variance that can also be set to 0.
@@ -182,3 +184,36 @@ If you have `gnuplot` installed this will also generate a plot of the resulting
182184

183185
A light color means that a node only has a one-way connection to the network, gray means a node is
184186
entirely isolated.
187+
188+
#### Manual Node placement
189+
190+
To manually put nodes on the 'map' by specifying their (x, y) coordinates, you can call `topogen` with
191+
a world file instead.
192+
193+
This is a simple text file that lists all nodes with their position and range:
194+
195+
```
196+
# name x y range
197+
A 5 3 10
198+
B 10
199+
C 20 20
200+
```
201+
202+
If `y` is left out, it defaults to 0.
203+
If `range` is left out, it defaults to 25.
204+
205+
Nodes can also be pinned to a (virtual) hardware address, for this declare the nodes before giving their coordinates:
206+
207+
```
208+
# name -> EUI-64 mapping
209+
A := 02:00:00:00:12:34:00:01
210+
B := 02:00:00:00:12:34:00:02
211+
C := 02:00:00:00:12:34:00:03
212+
213+
# name x y range
214+
A 5 3 10
215+
B 10
216+
C 20 20
217+
```
218+
219+
To generate the topology file from such a map, just run `bin/topopgen -f <worldfile>`.

dist/tools/zep_dispatch/topogen.c

Lines changed: 129 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
* License v2. See the file LICENSE for more details.
66
*/
77

8+
#include <ctype.h>
89
#include <stdbool.h>
910
#include <stdio.h>
1011
#include <stdint.h>
1112
#include <stdlib.h>
13+
#include <string.h>
1214
#include <time.h>
1315
#include <math.h>
1416
#include <unistd.h>
@@ -17,8 +19,12 @@
1719
#define CONFIG_USE_NUMERIC_NAMES 1
1820
#endif
1921

22+
#define DEFAULT_RANGE 25
23+
#define DELIM "\t ;,"
24+
2025
struct node {
21-
char name[8];
26+
char name[16];
27+
char extra[24];
2228
int x;
2329
int y;
2430
unsigned r;
@@ -194,7 +200,11 @@ static void _print_distance(struct node *nodes, unsigned num, bool recursive, bo
194200

195201
if (recursive) {
196202
for (unsigned i = 0; i < num; ++i) {
197-
printf("%s\n", nodes[i].name);
203+
printf("%s", nodes[i].name);
204+
if (*nodes[i].extra) {
205+
printf(" := %s", nodes[i].extra);
206+
}
207+
puts("");
198208
}
199209
}
200210

@@ -230,6 +240,7 @@ static void _print_help(const char *name)
230240
" [-r <range>]"
231241
" [-v <variance of range>]"
232242
" [-n <nodes>]"
243+
" [-f <file>]"
233244
" [-b][-g]"
234245
"\n", name);
235246

@@ -240,25 +251,116 @@ static void _print_help(const char *name)
240251
puts("\t-r <range>\tRadio range of the nodes");
241252
puts("\t-v <variance>\tmaximal random variance of radio range");
242253
puts("\t-n <nodes>\tnumber of nodes in the topology");
254+
puts("\t-f <file>\tread world from file instead of generating it randomly\n");
243255
puts("\t-b\t\tbinary links: link quality is rounded to 100% or 0%");
244256
puts("\t-g\t\tnodes are organized as a grid");
245257
}
246258

259+
static bool _is_empty(const char *line)
260+
{
261+
while (*line) {
262+
if (!isspace(*line++)) {
263+
return false;
264+
}
265+
}
266+
267+
return true;
268+
}
269+
270+
static struct node *_get_node_by_name(struct world *w, const char *name)
271+
{
272+
for (unsigned i = 0; i < w->num_nodes; ++i) {
273+
if (!strcmp(w->nodes[i].name, name)) {
274+
return &w->nodes[i];
275+
}
276+
}
277+
278+
return NULL;
279+
}
280+
281+
static int _from_file(struct world *w, FILE *file)
282+
{
283+
char *line = NULL;
284+
size_t len = 0;
285+
286+
287+
unsigned linenum = 0;
288+
while (getline(&line, &len, file) >= 0) {
289+
++linenum;
290+
291+
/* skip comments & empty lines */
292+
if (*line == '#' || _is_empty(line)) {
293+
continue;
294+
}
295+
296+
char *name = strtok(line, DELIM);
297+
char *xpos = strtok(NULL, DELIM);
298+
char *ypos = strtok(NULL, DELIM);
299+
char *range = strtok(NULL, DELIM);
300+
301+
/* check if node is already stored */
302+
struct node *n = _get_node_by_name(w, name);
303+
if (n == NULL) {
304+
w->nodes = reallocarray(w->nodes, ++w->num_nodes, sizeof(*w->nodes));
305+
n = &w->nodes[w->num_nodes - 1];
306+
}
307+
308+
/* store name */
309+
strncpy(n->name, name, sizeof(n->name) - 1);
310+
if (strlen(name) >= sizeof(n->name)) {
311+
fprintf(stderr, "warning: '%s' truncated to '%s'\n", name, n->name);
312+
}
313+
314+
/* node definition with pinned MAC */
315+
if (!strcmp(xpos, ":=")) {
316+
strncpy(n->extra, ypos, sizeof(n->extra) - 1);
317+
continue;
318+
}
319+
320+
if (xpos) {
321+
n->x = atoi(xpos);
322+
} else {
323+
fprintf(stderr, "error on line %d: '%s' has no position\n", linenum, name);
324+
return -1;
325+
}
326+
if (ypos) {
327+
n->y = atoi(ypos);
328+
}
329+
if (range) {
330+
n->r = atoi(range);
331+
} else {
332+
n->r = DEFAULT_RANGE;
333+
}
334+
335+
if (n->x + n->r > w->w) {
336+
w->w = n->x + n->r;
337+
}
338+
if (n->y + n->r > w->h) {
339+
w->h = n->y + n->r;
340+
}
341+
}
342+
343+
free(line);
344+
345+
return 0;
346+
}
347+
247348
int main(int argc, char** argv)
248349
{
249350
const char *progname = argv[0];
351+
char *worldmap = NULL;
250352

251353
unsigned width = 100;
252354
unsigned height = 100;
253355
unsigned seed = time(NULL);
254-
unsigned range = 25;
356+
unsigned range = DEFAULT_RANGE;
255357
unsigned var = 0;
256358
unsigned num = 10;
257359
bool binary = false;
258360
bool grid = false;
259361
char c;
260362

261-
while ((c = getopt(argc, argv, "s:w:h:r:v:n:bg")) != -1) {
363+
while ((c = getopt(argc, argv, "s:w:h:r:v:n:f:bg")) != -1) {
262364
switch (c) {
263365
case 'b':
264366
binary = true;
@@ -284,6 +386,9 @@ int main(int argc, char** argv)
284386
case 'n':
285387
num = atoi(optarg);
286388
break;
389+
case 'f':
390+
worldmap = optarg;
391+
break;
287392
default:
288393
_print_help(progname);
289394
exit(1);
@@ -295,7 +400,26 @@ int main(int argc, char** argv)
295400
struct world w = {
296401
.grid = grid,
297402
};
298-
world_gen(&w, num, width, height, range, var);
403+
404+
if (worldmap) {
405+
FILE *file;
406+
if (strcmp(worldmap, "-")) {
407+
file = fopen(worldmap, "r");
408+
} else {
409+
file = stdin;
410+
}
411+
if (!file) {
412+
fprintf(stderr, "can't open %s\n", worldmap);
413+
return -1;
414+
}
415+
int res = _from_file(&w, file);
416+
fclose(file);
417+
if (res) {
418+
return res;
419+
}
420+
} else {
421+
world_gen(&w, num, width, height, range, var);
422+
}
299423

300424
printf("# seed = %u\n", seed);
301425
puts("# Connections");

0 commit comments

Comments
 (0)