5 use Data::Dump qw(dump);
8 my $opt_svg = $ENV{SVG} || 0;
9 my $opt_alt = $ENV{ALT} || 0;
10 my $opt_invert = $ENV{INVERT} = 0;
11 my $opt_vertical = $ENV{VERTICAL} = 0;
12 my $opt_kernel = $ENV{kernel} = 1;
16 'invert!' => \$opt_invert,
17 'vertical!' => \$opt_vertical,
18 'kernel!' => \$opt_kernel,
22 my $font_w = 1.67; # < 2.54, font is not perfect square
23 my $font_b = 2.10; # font baseline position
26 open(my $fh, '<', shift);
33 my $model = slurp('/proc/device-tree/model');
34 $model =~ s/\x00$//; # strip kernel NULL
35 warn "# model [$model]";
44 warn "MODEL [$1] == [$model] ?\n";
45 if ( $model =~ m/$1/ ) {
50 } elsif ( m/^#\s+/ ) {
52 } elsif ( $include ) {
53 push @{ $pins->{$1} }, $line_i while ( m/\t(\w+\d+)/g );
59 warn "IGNORE: [$_]\n";
63 die "add pin definition for # $model" unless $pins;
65 warn "# pins ",dump($pins);
69 open(my $fh, '<', '/sys/kernel/debug/pinctrl/pinctrl-handles');
72 if ( m/group: (\w+\d+)\s.+function: (\S+)/ ) {
73 my ($pin, $function) = ($1,$2);
74 $pin_function->{$pin} = $function;
76 next unless $opt_kernel;
78 if ( $pins->{$pin} ) {
79 foreach my $line ( @{$pins->{$pin}} ) {
80 warn "XXX $pin $line";
81 my $t = $lines[$line];
83 $t =~ s/$pin/[$function]/;
85 $t =~ s/$pin/$pin [$function]/ || die "can't find $pin in [$t]";
88 warn "# $line: $lines[$line]\n";
91 warn "IGNORED: pin $pin function $function\n";
96 warn "# pin_function = ",dump($pin_function);
98 my @max_len = ( 0,0,0,0 );
100 foreach my $line (@lines) {
101 if ( $line =~ m/^#/ ) {
102 push @line_parts, [ $line ] unless $opt_svg;
105 $line =~ s/(\[uart\d)(\]\s[^\t]*(rx|tx))/$1 $3$2/gi;
106 $line =~ s/(\[i2c\d)(\]\s[^\t]*(sck|sda))/$1 $3$2/gi;
107 $line =~ s/(\[spi\d)(\]\s[^\t]*(miso|mosi|clk|cs))/$1 $3$2/gi;
108 $line =~ s/\s*\([^\)]+\)//g if ! $opt_alt;
110 my @v = split(/\s*\t+\s*/,$line,4);
111 push @line_parts, [ @v ];
112 foreach my $i ( 0 .. 3 ) {
113 next unless exists $v[$i];
114 next if $v[$i] =~ m/^#/; # don't calculate comments into max length
115 my $l = length($v[$i]);
116 $max_len[$i] = $l if $l > $max_len[$i];
120 warn "# max_len = ",dump( \@max_len );
121 warn "# line_parts = ",dump( \@line_parts );
123 #print "$_\n" foreach @lines;
125 my $fmt = "%$max_len[0]s %-$max_len[1]s %$max_len[2]s %-$max_len[3]s\n";
131 print qq{<?xml version="1.0" encoding="UTF-8" standalone="no"?>
133 xmlns:dc="http://purl.org/dc/elements/1.1/"
134 xmlns:cc="http://creativecommons.org/ns#"
135 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
136 xmlns:svg="http://www.w3.org/2000/svg"
137 xmlns="http://www.w3.org/2000/svg"
138 xmlns:xlink="http://www.w3.org/1999/xlink"
141 viewBox="0 0 210 297"
148 }; # svg, insert rest of rect
150 print qq{<rect x="0" y="0" width="210" height="297" style="fill:#000000" id="high-contrast"/>} if $opt_invert;
155 my $cols = { # foreground background
156 txt => [ '#000000', '#ffffff' ],
157 pins => [ '#ffffff', '#ff00ff' ],
158 vcc => [ '#ff0000', '#ffff00' ],
159 gnd => [ '#000000', '#00ffff' ],
160 i2c => [ '#008800', '#ffcccc' ],
161 uart => [ '#000088', '#ccffcc' ],
162 spi => [ '#880000', '#ccccff' ],
167 die "$swap not found in ",dump($cols) unless $cols->{$swap};
168 my ( $c1, $c2 ) = @{ $cols->{$swap} };
169 $cols->{$swap} = [ $c2, $c1 ];
172 swap_cols 'txt' if $opt_invert;
176 my ($name,$x,$y,$col) = @_;
177 $y -= $font_b; # shift box overlay to right vertical position based on font baseline
180 my ($x,$y,$col,$fill) = @_;
181 print qq{<rect x="$x" y="$y" height="2.54" width="}, $max_len[$col] * $font_w, qq{" style="opacity:1;fill:$fill;stroke:#ffffff;stroke-width:0.10" />\n};
185 if ( $name =~ m/^(\d+)$/ ) { # pins
187 my ( $fg, $bg ) = @{ $cols->{pins} };
189 my $w = $max_len[$col]*$font_w - 0.1;
192 #print qq{<polygon points="$x,$y $cx,$y $x,$cy $x,$y" stroke="$fg" stroke-width="0.25" fill="$bg" />};
193 #print qq{<polygon points="$x,$cy $cx,$cy $cx,$y $x,$cy" stroke="$bg" stroke-width="0.25" fill="$fg" />};
194 print qq{<rect x="$x" y="$y" width="$w" height="2.54" stroke="$fg" stroke-width="0.3" fill="$bg" />};
195 my ( $fg, $bg ) = @{ $cols->{txt} };
196 print qq{<rect x="$x" y="$y" width="$w" height="2.54" rx="1" ry="1" stroke="$fg" stroke-width="0.3" fill="$bg" />};
200 return qq{ style="fill:$bg"};
203 if ( $name =~ m/(VCC|3V3|3.3V)/i ) {
204 my ($fg,$bg) = @{ $cols->{vcc} };
206 return qq{ style="fill:$fg"};
207 } elsif ( $name =~ m/(G(ND|Round)|VSS)/i ) {
208 my ($fg,$bg) = @{ $cols->{gnd} };
210 return qq{ style="fill:$fg"};
211 } elsif ( $name =~ m/\[(\w+)\d/ ) { # kernel
213 if ( my ($fg,$bg) = @{ $cols->{$dev} } ) {
215 return qq{ style="fill:$fg"};
218 my ( $fg, $bg ) = @{ $cols->{txt} };
220 #return qq{ style="fill:$fg"};
227 my @cols_order = ( 0,1,2,3 );
228 my @cols_align = ( '','-','','-' ); # sprintf prefix
230 @cols_order = ( 0,1,3,2 ); # pins outside on the right
231 @cols_align = ( '','-','-','' );
235 my ($fg,$bg) = @{ $cols->{txt} };
236 my $line_fmt = qq{<line x1="%s" y1="%s" x2="%s" y2="%s" style="stroke:$fg;stroke-width:0.10;fill:$bg" />\n};
241 return unless $opt_svg;
242 push @cut_marks, sprintf($line_fmt, $x-5, $y-$font_b, $x+5, $y-$font_b);
243 push @cut_marks, sprintf($line_fmt, $x, $y-$font_b-5, $x, $y-$font_b+5);
247 $max_x += $max_len[$_] * $font_w foreach ( 0 .. 3 );
250 my $last_cut_mark = 0;
252 foreach my $i ( 0 .. $#line_parts ) {
253 $i = $#line_parts - $i if $opt_vertical;
254 my $line = $line_parts[$i];
258 if ( ! exists $line->[0] ) {
259 # before first empty line
260 if ( $last_cut_mark == 0 ) {
264 $y += 15; # make spacing between pinouts
266 } elsif ( $last_cut_mark ) {
272 #warn "CUTMARK no magic";
275 my ($fg,$bg) = @{ $cols->{txt} };
276 my $tspan = qq{<tspan x="$x" y="$y" style="line-height:2.54;fill-opacity:1;fill:$fg;stroke:none;">\n};
279 foreach my $i ( @cols_order ) {
280 next unless $line->[$i];
281 my $text_anchor = 'middle';
282 my $x2 = $x_pos + ( $max_len[$i] * $font_w ) / 2;
283 $tspan .= qq{<tspan x="$x2" text-anchor="$text_anchor"}.svg_style($line->[$i],$x_pos,$y,$i).sprintf( '>%' . $cols_align[$i] . $max_len[$i] . 's</tspan>', $line->[$i]);
284 $x_pos += $max_len[$i] * $font_w;
287 $tspan .= qq{</tspan>\n};
288 push @later,sprintf $tspan, @$line;
291 # swap pin colors for line stripes
292 swap_cols $_ foreach qw( pins txt );
296 if ( $#$line == 0 ) {
297 print $line->[0], "\n";
299 push @$line, '' while ($#$line < 3); # fill-in single row header
312 style="font-size:2.34px;line-height:2.54px;font-family:'Andale Mono';fill-opacity:1;stroke:none;stroke-opacity:1"
313 xml:space="preserve">
317 print @later, qq{</text>\n}, @cut_marks, qq{</g>\n</svg>};
322 # Cubietech Cubieboard2
323 ## U14 (Next to SATA connector)
325 48 PI13 (SPI0-MISO/UART6-RX/EINT25) 47 PI11 (SPI0-CLK/UART5-RX/EINT23)
326 46 PI12 (SPI0-MOSI/UART6-TX/EINT24) 45 PI10 (SPI0-CS/UART5-TX/EINT22)
328 44 3.3V (nc in 2012-08-08) 43 VCC-5V
330 40 PB10 (LCD0-SCK/LCD-PIO1) 39 PB11 (LCD0-SDA/LCD-PIO2)
331 38 Ground 37 PH7 (LCD0-BL-EN/LCD-PIO0/UART5-RX/EINT7)
332 36 XN_TP (TP-X2) 35 YN_TP (TP-Y2)
333 34 XP_TP (TP-X1) 33 YP_TP (TP-Y1)
334 32 PD25 (LCDDE) 31 PB2 (PWM0)
335 30 PD26 (LCDHSYNC/VGA-HSYNC) 29 PD24 (LCDCLK)
336 28 PD23 (LCDD23) 27 PD27 (LCDVSYNC/VGA-VSYNC)
337 26 PD21 (LCDD21) 25 PD22 (LCDD22)
338 24 PD19 (LCDD19/LVDS1N3) 23 PD20 (LCDD20)
339 22 PD17 (LCDD17/LVDS1NC) 21 PD18 (LCDD18/LVDS1P3)
340 20 Ground 19 PD16 (LCDD16/LVDS1PC)
341 18 PD14 (LCDD14/LVDS1P2) 17 PD15 (LCDD15/LVDS1N2)
342 16 PD12 (LCDD12/LVDS1P1) 15 PD13 (LCDD13/LVDS1N1)
343 14 PD10 (LCDD10/LVDS1P0) 13 PD11 (LCDD11/LVDS1N0)
344 12 PD8 (LCDD8/LVDS0P3) 11 PD9 (LCDD9/LVDS0N3)
345 10 PD7 (LCDD7/LVDS0NC) 9 Ground
346 8 PD5 (LCDD5/LVDS0N2) 7 PD6 (LCDD6/LVDS0PC)
347 6 PD3 (LCDD3/LVDS0N1) 5 PD4 (LCDD4/LNVS0P2)
348 4 PD1 (LCDD1/LVDS0N0) 3 PD2 (LCDD2/LVDS0P1)
349 2 Ground 1 PD0 (LCDD0/LVDSP0)
351 # Cubietech Cubieboard2
352 ## U15 (Between Ethernet port and USB ports)
354 1 VCC-5V 2 PH15 (CSI1-PWR/EINT15)
355 3 CSI1-IO-2V8 4 PH14 (CSI1-RST#/EINT14)
356 5 PG0 (CSI1-PCLK/SDC1-CMD) 6 PB18 (TWI1-SCK)
357 7 PB19 (TWI1-SDA) 8 PG3 (CSI1-VSYNC/SDC1-D1)
358 9 PG2 (CSI1-HSYNC/SDC1-D0) 10 PG1 (CSI1-MCLK/SDC1-CLK)
359 11 PG4 (CSI1-D0/SDC1-D2) 12 PG5 (CSI1-D1/SDC1-D3)
360 13 PG6 (CSI1-D2/UART3-TX) 14 PG7 (CSI1-D3/UART3-RX)
361 15 PG8 (CSI1-D4/UART3-RTS) 16 PG9 (CSI1-D5/UART3-CTS)
362 17 PG10 (CSI1-D6/UART4-TX) 18 PG11 (CSI1-D7/UART4-RX)
365 21 FMINL 22 PI4 (SDC3-CMD)
366 23 FMINR 24 PI5 (SDC3-CLK)
367 25 Ground 26 PI6 (SDC3-D0)
368 27 VGA-R 28 PI7 (SDC3-D1)
369 29 VGA-G 30 PI8 (SDC3-D2)
370 31 VGA-B 32 PI9 (SDC3-D3)
372 33 LCD1-VSYNC 34 PE4 (CSI0-D0)
373 35 LCD1-HSYNC 36 PE5 (CSI0-D1)
374 37 Ground 38 PE6 (CSI0-D2)
375 39 AVCC 40 PE7 (CSI0-D3)
376 41 LRADC0 42 PE8 (CSI0-D4)
377 43 CVBS 44 PE9 (CSI0-D5)
378 45 HPL 46 PE10 (CSI0-D6)
379 47 HPR 48 PE11 (CSI0-D7)
381 ## DEBUG serial (middle of board)
389 ## CON3 rpi DIP26-254
393 7 PI3 PWM1 8 PH0 UART3_TX
395 11 PI19 UART2_RX 12 PH2
396 13 PI18 UART2_TX 14 0v
397 15 PI17 UART2_CTS 16 PH21 CAN_RX
398 17 3.3v 18 PH20 CAN_TX
399 19 PI12 SPI0_MOSI 20 0v
400 21 PI13 SPI0_MISO 22 PI16 UART2_RTS
401 23 PI11 SPI0_SCLK 24 PI10 SPI0_CS0
402 25 0v 26 PI14 SPI0_CS1
410 6 PI20 UART7_TX 5 PH3
411 4 PI21 UART7_RX 3 PH5
414 # Raspberry Pi 3 Model B Rev 1.2
418 7 gpio4 (GPIO. 7) 8 gpio14 (TxD)
420 11 gpio17 (GPIO. 0) 12 gpio18 (GPIO. 1)
421 13 gpio27 (GPIO. 2) 14 0v
422 15 gpio22 (GPIO. 3) 16 gpio23 (GPIO. 4)
423 17 3.3v 18 gpio24 (GPIO. 5)
424 19 gpio10 (MOSI) 20 0v
425 21 gpio9 (MISO) 22 gpio25 (GPIO. 6)
426 23 gpio11 (SCLK) 24 gpio8 (CE0)
428 27 gpio0 (SDA.0) 28 gpio1 (SCL.0)
429 29 gpio5 (GPIO.21) 30 0v
430 31 gpio6 (GPIO.22) 32 gpio12 (GPIO.26)
431 33 gpio13 (GPIO.23) 34 0v
432 35 gpio19 (GPIO.24) 36 gpio16 (GPIO.27)
433 37 gpio26 (GPIO.25) 38 gpio20 (GPIO.28)
434 39 0v 40 gpio21 (GPIO.29)