diff --git a/scripts/single-sku.pl b/scripts/single-sku.pl new file mode 100644 index 00000000..8c43556a --- /dev/null +++ b/scripts/single-sku.pl @@ -0,0 +1,333 @@ +#!/usr/bin/perl +use strict; +use 5.010; + +my $indent = 0; + +my %chip_types = ( + mt7615 => "mt7615", + mt7622 => "mt7615", + mt7663 => "mt7615" +); + +my $chip = shift @ARGV; +my $chip_type; + +$chip or usage(); + +sub usage() { + print STDERR < [options] [[options] ...] + +Options: + country=XX: Set country code + regdomain=XX: Set regdomain + +Multiple country codes/regdomains per file are supported + +EOF + exit(1); +} + +sub convert_array($) { + my $array = shift; + + return unless $array; + foreach my $i (0 .. $#{$array}) { + $array->[$i] = int($array->[$i] * 2); + } + + return $array; +} + +sub parse_channel($$$) { + my $band = shift; + my $channels = $band->{channels}; + + my $ch = shift; + my $line = shift; + + my @data = split /\s+/, $line; + my $data = join(" ", @data); + + my $channel = { + chlist => [ ], + data => $data, + mcs => [], + }; + + $channels->{$ch} = $channel; + + $band->{type} eq '2' and do { + $channel->{cck} = convert_array([ + $data[0], $data[0], + $data[1], $data[1] + ]); + splice @data, 0, 2; + }; + + $channel->{ofdm} = convert_array([ + $data[0], $data[0], + $data[1], $data[1], + $data[2], $data[2], + $data[3], $data[4] + ]); + splice @data, 0, 5; + + my @bw = ( "bw20", "bw40", "bw80", "bw160" ); + $band->{type} eq '2' and @bw = ( "bw20", "bw40" ); + + foreach my $bw (@bw) { + push @{$channel->{mcs}}, convert_array([ + $data[0], + $data[1], $data[1], + $data[2], $data[2], + $data[3], $data[3], + $data[4], + $data[5], + $data[6], + ]); + splice @data, 0, 7; + }; + + @data > 0 and do { + $channel->{"txs-delta"} = convert_array([ reverse splice @data, 0, 3 ]); + delete $channel->{"txs-delta"} if join("", @{$channel->{"txs-delta"}}) =~ /^0+$/; + }; +} + +sub read_data($) { + my $file = shift; + my $band; + my %bands; + + open FILE, "<", $file or die "Can't open file $file\n"; + while () { + chomp; + + /^Band: (2.4|5)G / and do { + $band = $1; + $band eq '2.4' and $band = "2"; + $bands{$band} = { + type => $band, + channels => {}, + }; + }; + /^Ch(\d+)\s+(.+?)\s*$/ and parse_channel($bands{$band}, $1, $2); + } + close FILE; + + return \%bands; +} + +sub find_matching_channel($$) { + my $band = shift; + my $channels = $band->{channels}; + + my $ch_idx = shift; + my $ch = $channels->{$ch_idx}; + + foreach my $cur (sort { $a <=> $b } keys %$channels) { + my $cur_ch; + + return undef if $cur >= $ch_idx; + + $cur_ch = $channels->{$cur}; + $cur_ch->{data} eq $ch->{data} and return $cur_ch; + } +} + +sub optimize_channels($) { + my $band = shift; + my $channels = $band->{channels}; + my $prev; + my $prev_chlist; + + foreach my $ch_idx (sort { $a <=> $b } keys %$channels) { + my $ch = $channels->{$ch_idx}; + + $prev and ($ch->{data} eq $prev->{data}) and do { + $prev_chlist->[1] = $ch_idx; + delete $channels->{$ch_idx}; + next; + }; + + $prev = find_matching_channel($band, $ch_idx); + if ($prev) { + delete $channels->{$ch_idx}; + } else { + $prev = $ch; + } + + $prev_chlist = [ $ch_idx, $ch_idx ]; + push @{$prev->{chlist}}, $prev_chlist; + } +} + +sub add_line { + my $line = shift; + print "".("\t" x $indent).$line; +} + +sub array_str($) { + my $a = shift; + + return "<".join(" ", @$a).">"; +} + +sub string_array_str($) { + my $a = shift; + + return join(", ", map { "\"$_\"" } @$a); +} + +sub add_named_array($$) { + my $ch = shift; + my $type = shift; + + return unless $ch->{$type}; + add_line("$type = ".array_str($ch->{$type}).";\n"); +} + +sub add_named_string_array($$) { + my $ch = shift; + my $type = shift; + + return unless $ch->{$type} and @{$ch->{$type}} > 0; + add_line("$type = ".string_array_str($ch->{$type}).";\n"); +} + +sub add_multi_array($$) { + my $name = shift; + my $a = shift; + + add_line("$name ="); + if (@$a > 1) { + my $first = 1; + + print "\n"; + $indent++; + foreach my $v (@$a) { + $first or print ",\n"; + undef $first; + + add_line(array_str($v)); + } + $indent--; + } else { + print " ".array_str($a->[0]); + } + print ";\n"; +} + +sub print_txpower($) { + my $ch = shift; + my @data; + + add_named_array($ch, "txs-delta"); + add_named_array($ch, "cck"); + add_named_array($ch, "ofdm"); + + my $prev; + foreach my $v (@{$ch->{mcs}}) { + my $val = [1, @{$v}]; + + if ($prev and (array_str($v) eq array_str($prev))) { + $data[$#data]->[0]++; + } else { + push @data, $val; + } + + $prev = $v; + } + + add_multi_array("mcs", \@data); +}; + +sub print_channels($) { + my $band = shift; + my $channels = $band->{channels}; + my $r = 0; + + foreach my $ch_idx (sort { $a <=> $b } keys %$channels) { + my $ch = $channels->{$ch_idx}; + my $first = 1; + + add_line("r$r {\n"); + $indent++; + + add_multi_array("channels", $ch->{chlist}); + print_txpower($ch); + + $indent--; + add_line("};\n"); + + $r++; + } +} + +sub print_bands($) { + my $bands = shift; + + foreach my $band_idx (sort keys %$bands) { + my $band = $bands->{$band_idx}; + + optimize_channels($band); + + add_line("txpower-".$band->{type}."g {\n"); + $indent++; + + print_channels($band); + + $indent--; + add_line("};\n"); + }; +} + +my @files; +my $cur = {}; + +$chip_type = $chip_types{$chip} or die "Unsupported chip type '$chip', supported chip types: ".join(", ",sort keys %chip_types)."\n"; + +while (@ARGV > 0) { + my $arg = shift @ARGV; + + $cur or $cur = { + country => [], + regdomain => [], + }; + + if ($arg =~ /country=(\w+)$/) { + push @{$cur->{country}}, $1; + } elsif ($arg =~ /regdomain=(\w+)$/) { + push @{$cur->{regdomain}}, $1; + } else { + $cur->{bands} = read_data($arg); + push @files, $cur; + $cur = undef; + } +} + + +add_line("power-limits {\n"); +$indent++; + +my $count = 0; + +foreach my $domain (@files) { + my $name = "r$count"; + $count++; + + add_line("$name {\n"); + $indent++; + + add_named_string_array($domain, "country"); + add_named_string_array($domain, "regdomain"); + print_bands($domain->{bands}); + + $indent--; + add_line("};\n"); +} + +$indent--; +add_line("};\n");