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, printf($line_fmt, $x-5, $y-$font_b, $x+5, $y-$font_b);
243 push @cut_marks, printf($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, @cut_marks, qq{
326 # Cubietech Cubieboard2
327 ## U14 (Next to SATA connector)
329 48 PI13 (SPI0-MISO/UART6-RX/EINT25) 47 PI11 (SPI0-CLK/UART5-RX/EINT23)
330 46 PI12 (SPI0-MOSI/UART6-TX/EINT24) 45 PI10 (SPI0-CS/UART5-TX/EINT22)
332 44 3.3V (nc in 2012-08-08) 43 VCC-5V
334 40 PB10 (LCD0-SCK/LCD-PIO1) 39 PB11 (LCD0-SDA/LCD-PIO2)
335 38 Ground 37 PH7 (LCD0-BL-EN/LCD-PIO0/UART5-RX/EINT7)
336 36 XN_TP (TP-X2) 35 YN_TP (TP-Y2)
337 34 XP_TP (TP-X1) 33 YP_TP (TP-Y1)
338 32 PD25 (LCDDE) 31 PB2 (PWM0)
339 30 PD26 (LCDHSYNC/VGA-HSYNC) 29 PD24 (LCDCLK)
340 28 PD23 (LCDD23) 27 PD27 (LCDVSYNC/VGA-VSYNC)
341 26 PD21 (LCDD21) 25 PD22 (LCDD22)
342 24 PD19 (LCDD19/LVDS1N3) 23 PD20 (LCDD20)
343 22 PD17 (LCDD17/LVDS1NC) 21 PD18 (LCDD18/LVDS1P3)
344 20 Ground 19 PD16 (LCDD16/LVDS1PC)
345 18 PD14 (LCDD14/LVDS1P2) 17 PD15 (LCDD15/LVDS1N2)
346 16 PD12 (LCDD12/LVDS1P1) 15 PD13 (LCDD13/LVDS1N1)
347 14 PD10 (LCDD10/LVDS1P0) 13 PD11 (LCDD11/LVDS1N0)
348 12 PD8 (LCDD8/LVDS0P3) 11 PD9 (LCDD9/LVDS0N3)
349 10 PD7 (LCDD7/LVDS0NC) 9 Ground
350 8 PD5 (LCDD5/LVDS0N2) 7 PD6 (LCDD6/LVDS0PC)
351 6 PD3 (LCDD3/LVDS0N1) 5 PD4 (LCDD4/LNVS0P2)
352 4 PD1 (LCDD1/LVDS0N0) 3 PD2 (LCDD2/LVDS0P1)
353 2 Ground 1 PD0 (LCDD0/LVDSP0)
355 # Cubietech Cubieboard2
356 ## U15 (Between Ethernet port and USB ports)
358 1 VCC-5V 2 PH15 (CSI1-PWR/EINT15)
359 3 CSI1-IO-2V8 4 PH14 (CSI1-RST#/EINT14)
360 5 PG0 (CSI1-PCLK/SDC1-CMD) 6 PB18 (TWI1-SCK)
361 7 PB19 (TWI1-SDA) 8 PG3 (CSI1-VSYNC/SDC1-D1)
362 9 PG2 (CSI1-HSYNC/SDC1-D0) 10 PG1 (CSI1-MCLK/SDC1-CLK)
363 11 PG4 (CSI1-D0/SDC1-D2) 12 PG5 (CSI1-D1/SDC1-D3)
364 13 PG6 (CSI1-D2/UART3-TX) 14 PG7 (CSI1-D3/UART3-RX)
365 15 PG8 (CSI1-D4/UART3-RTS) 16 PG9 (CSI1-D5/UART3-CTS)
366 17 PG10 (CSI1-D6/UART4-TX) 18 PG11 (CSI1-D7/UART4-RX)
369 21 FMINL 22 PI4 (SDC3-CMD)
370 23 FMINR 24 PI5 (SDC3-CLK)
371 25 Ground 26 PI6 (SDC3-D0)
372 27 VGA-R 28 PI7 (SDC3-D1)
373 29 VGA-G 30 PI8 (SDC3-D2)
374 31 VGA-B 32 PI9 (SDC3-D3)
376 33 LCD1-VSYNC 34 PE4 (CSI0-D0)
377 35 LCD1-HSYNC 36 PE5 (CSI0-D1)
378 37 Ground 38 PE6 (CSI0-D2)
379 39 AVCC 40 PE7 (CSI0-D3)
380 41 LRADC0 42 PE8 (CSI0-D4)
381 43 CVBS 44 PE9 (CSI0-D5)
382 45 HPL 46 PE10 (CSI0-D6)
383 47 HPR 48 PE11 (CSI0-D7)
385 ## DEBUG serial (middle of board)
393 ## CON3 rpi DIP26-254
397 7 PI3 PWM1 8 PH0 UART3_TX
399 11 PI19 UART2_RX 12 PH2
400 13 PI18 UART2_TX 14 0v
401 15 PI17 UART2_CTS 16 PH21 CAN_RX
402 17 3.3v 18 PH20 CAN_TX
403 19 PI12 SPI0_MOSI 20 0v
404 21 PI13 SPI0_MISO 22 PI16 UART2_RTS
405 23 PI11 SPI0_SCLK 24 PI10 SPI0_CS0
406 25 0v 26 PI14 SPI0_CS1
414 6 PI20 UART7_TX 5 PH3
415 4 PI21 UART7_RX 3 PH5
418 # Raspberry Pi 3 Model B Rev 1.2
422 7 gpio4 (GPIO. 7) 8 gpio14 (TxD)
424 11 gpio17 (GPIO. 0) 12 gpio18 (GPIO. 1)
425 13 gpio27 (GPIO. 2) 14 0v
426 15 gpio22 (GPIO. 3) 16 gpio23 (GPIO. 4)
427 17 3.3v 18 gpio24 (GPIO. 5)
428 19 gpio10 (MOSI) 20 0v
429 21 gpio9 (MISO) 22 gpio25 (GPIO. 6)
430 23 gpio11 (SCLK) 24 gpio8 (CE0)
432 27 gpio0 (SDA.0) 28 gpio1 (SCL.0)
433 29 gpio5 (GPIO.21) 30 0v
434 31 gpio6 (GPIO.22) 32 gpio12 (GPIO.26)
435 33 gpio13 (GPIO.23) 34 0v
436 35 gpio19 (GPIO.24) 36 gpio16 (GPIO.27)
437 37 gpio26 (GPIO.25) 38 gpio20 (GPIO.28)
438 39 0v 40 gpio21 (GPIO.29)