aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-07-09 09:20:42 +0200
committerHarald Welte <laforge@gnumonks.org>2010-07-09 09:20:42 +0200
commita831a2a80b54d428031e64c37321003c7157bd56 (patch)
tree56782e5b1d02eb8321d29a97e3d9760796fa97a3
initial commit of tool to generate ladder diagrams
-rw-r--r--Makefile16
-rwxr-xr-xgen_ladder.pl156
-rw-r--r--test.lad19
3 files changed, 191 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a02d73a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,16 @@
+GL=./gen_ladder.pl
+DOT=dot
+
+default:
+
+%.dot: %.lad
+ $(GL) $^ > $@
+
+%.ps: %.dot
+ $(DOT) -Tps < $^ > $@
+
+%.svg: %.dot
+ $(DOT) -Tsvg < $^ > $@
+
+clean:
+ rm *.dot *.ps *.svg
diff --git a/gen_ladder.pl b/gen_ladder.pl
new file mode 100755
index 0000000..d36b9e8
--- /dev/null
+++ b/gen_ladder.pl
@@ -0,0 +1,156 @@
+#!/usr/bin/perl -w
+use strict;
+
+# Script to generate Graphviz (.dot) based ladder diagrams for network
+# protocols
+#
+# (C) 2010 by Harald Welte <laforge@gnumonks.org>
+
+my $cfg_parse_state;
+my $cfg_parse_section;
+
+my %cfg_entities;
+my @cfg_entity_arr;
+my $cfg_nr_entities = 0;
+my @cfg_messages;
+
+# parse a line of the config file
+sub parse_cfg_line($)
+{
+ my $line = shift;
+
+ if ($line =~ /^\#/ ||
+ $line =~ /^\s*$/) {
+ return;
+ }
+
+ #printf("sec=%s\n", $cfg_parse_section);
+ if ($line =~ /^\[/) {
+ ($cfg_parse_section) = $line =~ /^\[(.*)\]/;
+ return;
+ }
+ if ($cfg_parse_section eq 'entities') {
+ my ($entity) = $line =~ /^(\w+)/;
+ $cfg_entities{$entity} = $cfg_nr_entities++;
+ push(@cfg_entity_arr, $entity);
+ } elsif ($cfg_parse_section eq 'messages') {
+ my ($src, $dst, $label, $flags) =
+ $line =~ /(\w+)\s+(\w+)\s+"(.*)"(.*)/;
+ my %msg;
+ $msg{'src'} = $src;
+ $msg{'dst'} = $dst;
+ $msg{'label'} = $label;
+ $msg{'flags'} = $flags;
+ # store a reference to the new hash on the global pile of
+ # message hash references
+ #print("$src $dst $label $flags\n");
+ push(@cfg_messages, \%msg);
+ }
+}
+
+# parse a line of the config file
+sub parse_cfg_file($)
+{
+ my $fname = shift;
+ open(INFILE, "<$fname");
+ while (my $line = <INFILE>) {
+ #print($line);
+ chomp($line);
+ parse_cfg_line($line);
+ }
+ close(INFILE);
+}
+
+# generate the nodes between which we will transfer messages
+sub gen_nodes()
+{
+ my $num_msgs = @cfg_messages;
+
+ foreach my $m (@cfg_entity_arr) {
+ printf(" %s [shape=none]\n", $m);
+ }
+ print("\n");
+
+ foreach my $m (@cfg_entity_arr) {
+ my $first = 0;
+ my $count;
+
+ # initial edge between header entity and the chain
+ printf(" %s -> %s0 [style=invis]\n", $m, $m);
+
+ # chain of edges between the individual nodes of one entity
+ for ($count = 0; $count < $num_msgs+1; $count++) {
+ my $name = sprintf("%s%u", $m, $count);
+ if ($first == 0) {
+ printf(" %s ", $name);
+ } else {
+ printf("-> %s ", $name);
+ }
+ $first = 1;
+ }
+ print(" [weight=1000]\n");
+ }
+ print("\n");
+
+ # invisible chain of edges between all entities
+ my $first = 1;
+ print(" { rank=same;\n edge[style=invis]\n");
+ foreach my $e (@cfg_entity_arr) {
+ if ($first) {
+ printf(" %s0 ", $e);
+ $first = 0;
+ } else {
+ printf("-> %s0 ", $e);
+ }
+ }
+ print("\n }\n");
+ print("\n");
+}
+
+sub entity_left_of($$)
+{
+ my $l = shift;
+ my $r = shift;
+ if ($cfg_entities{$l} < $cfg_entities{$r}) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+# generate edges for the individual messages
+sub gen_edges()
+{
+ my $count = 1;
+ my $l; my $r; my $dir;
+
+ foreach my $m (@cfg_messages) {
+ if (entity_left_of($$m{'src'}, $$m{'dst'})) {
+ $l = $$m{'src'};
+ $r = $$m{'dst'};
+ $dir = 'forward';
+ } else {
+ $l = $$m{'dst'};
+ $r = $$m{'src'};
+ $dir = 'back';
+ }
+ print(" { rank=same;\n");
+ printf(" %s%u -> %s%u [dir=%s label=\"%s\"]\n }\n",
+ $l, $count, $r, $count, $dir, $$m{'label'});
+ $count++;
+ }
+}
+
+parse_cfg_file($ARGV[0]);
+
+# print static header
+print("digraph ladder {\n");
+print(" node [shape=point]\n");
+print(" edge [dir=none]\n");
+
+# generate and print dynamic content
+gen_nodes();
+gen_edges();
+
+# print footer
+print("}\n");
diff --git a/test.lad b/test.lad
new file mode 100644
index 0000000..360b091
--- /dev/null
+++ b/test.lad
@@ -0,0 +1,19 @@
+[entities]
+# define the entities in the system (in order)
+ms
+bts
+bsc
+msc
+hlr
+
+[messages]
+# define the protocol messages in-order
+ms bts "L1 RACH burst"
+bts bsc "RSL CHAN RQD"
+bsc bts "RSL CHAN ACT REQ"
+bts bsc "RSL CHAN ACT ACK"
+bsc bts "RSL IMM ASS CMD"
+bts ms "IMMEDIATE ASSIGN"
+ms bsc "CM SERVICE REQUEST"
+bsc msc "COMPL L3 INFO (CM SERV REQ)"
+ms msc "Dedicated Channel" both dashed