From a831a2a80b54d428031e64c37321003c7157bd56 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 9 Jul 2010 09:20:42 +0200 Subject: [PATCH] initial commit of tool to generate ladder diagrams --- Makefile | 16 ++++++ gen_ladder.pl | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++ test.lad | 19 ++++++ 3 files changed, 191 insertions(+) create mode 100644 Makefile create mode 100755 gen_ladder.pl create mode 100644 test.lad 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 + +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 = ) { + #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