working on rpi 3, not really useful on old 4.9 kernel
[linux-gpio-pinout] / gpio.pl
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4 use autodie;
5 use Data::Dump qw(dump);
6 use Getopt::Long;
7
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;
13 GetOptions(
14         'svg!' => \$opt_svg,
15         'alt!' => \$opt_alt,
16         'invert!' => \$opt_invert,
17         'vertical!' => \$opt_vertical,
18         'kernel!' => \$opt_kernel,
19 );
20
21 # svg font hints
22 my $font_w = 1.67; # < 2.54, font is not perfect square
23 my $font_b = 2.10; # font baseline position
24
25 sub slurp {
26         open(my $fh, '<', shift);
27         local $/ = undef;
28         <$fh>;
29 }
30
31 my $pins;
32
33 my $model = slurp('/proc/device-tree/model');
34 $model =~ s/\x00$//; # strip kernel NULL
35 warn "# model [$model]";
36
37 my @lines;
38 my $line_i = 0;
39
40 my $include = 0;
41 while(<DATA>) {
42         chomp;
43         if ( m/^#\s(.+)/ ) {
44                 warn "MODEL [$1] == [$model] ?\n";
45                 if ( $model =~ m/$1/ ) {
46                         $include = 1;
47                 } else {
48                         $include = 0;
49                 }
50         } elsif ( m/^#\s+/ ) {
51                 $include = 1;
52         } elsif ( $include ) {
53                 push @{ $pins->{$1} }, $line_i while ( m/\t(\w+\d+)/g );
54
55                 push @lines, $_;
56
57                 $line_i++;
58         } else {
59                 warn "IGNORE: [$_]\n";
60         }
61 }
62
63 die "add pin definition for # $model" unless $pins;
64
65 warn "# pins ",dump($pins);
66
67 my $pin_function;
68
69 open(my $fh, '<', '/sys/kernel/debug/pinctrl/pinctrl-handles');
70 while(<$fh>) {
71         chomp;
72         if ( m/group: (\w+\d+)\s.+function: (\S+)/ ) {
73                 my ($pin, $function) = ($1,$2);
74                 $pin_function->{$pin} = $function;
75
76                 next unless $opt_kernel;
77
78                 if ( $pins->{$pin} ) {
79                         foreach my $line ( @{$pins->{$pin}} ) {
80 warn "XXX $pin $line";
81                                 my $t = $lines[$line];
82                                 if ( $opt_svg ) {
83                                         $t =~ s/$pin/[$function]/;
84                                 } else {
85                                         $t =~ s/$pin/$pin [$function]/ || die "can't find $pin in [$t]";
86                                 }
87                                 $lines[$line] = $t;
88                                 warn "# $line: $lines[$line]\n";
89                         }
90                 } else {
91                         warn "IGNORED: pin $pin function $function\n";
92                 }
93         }
94 }
95
96 warn "# pin_function = ",dump($pin_function);
97
98 my @max_len = ( 0,0,0,0 );
99 my @line_parts;
100 foreach my $line (@lines) {
101         if ( $line =~ m/^#/ ) {
102                 push @line_parts, [ $line ] unless $opt_svg;
103                 next;
104         }
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;
109
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];
117         }
118 }
119
120 warn "# max_len = ",dump( \@max_len );
121 warn "# line_parts = ",dump( \@line_parts );
122
123 #print "$_\n" foreach @lines;
124
125 my $fmt = "%$max_len[0]s %-$max_len[1]s %$max_len[2]s %-$max_len[3]s\n";
126
127 my $x = 30.00; # mm
128 my $y = 30.00; # mm
129
130 if ( $opt_svg ) {
131         print qq{<?xml version="1.0" encoding="UTF-8" standalone="no"?>
132 <svg
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"
139    id="svg8"
140    version="1.1"
141    viewBox="0 0 210 297"
142    height="297mm"
143    width="210mm">
144
145
146 <g id="layer1">
147
148         }; # svg, insert rest of rect
149
150         print qq{<rect x="0" y="0" width="210" height="297" style="fill:#000000" id="high-contrast"/>} if $opt_invert;
151 }
152
153 my @later;
154
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' ],
163 };
164
165 sub swap_cols {
166         my $swap = shift;
167         die "$swap not found in ",dump($cols) unless $cols->{$swap};
168         my ( $c1, $c2 ) = @{ $cols->{$swap} };
169         $cols->{$swap} = [ $c2, $c1 ];
170 }
171
172 swap_cols 'txt' if $opt_invert;
173         
174
175 sub svg_style {
176         my ($name,$x,$y,$col) = @_;
177         $y -= $font_b; # shift box overlay to right vertical position based on font baseline
178
179         sub rect {
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};
182
183         }
184
185         if ( $name =~ m/^(\d+)$/ ) { # pins
186                 my $pin = $1;
187                 my ( $fg, $bg ) = @{ $cols->{pins} };
188                 if ( $pin == 1 ) {
189                         my $w  = $max_len[$col]*$font_w - 0.1;
190                         my $cx = $x + $w;
191                         my $cy = $y + 2.54;
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" />};
197                 } else {
198                         rect $x,$y,$col,$fg;
199                 }
200                 return qq{ style="fill:$bg"};
201         }
202
203         if ( $name =~ m/(VCC|3V3|3.3V)/i ) {
204                 my ($fg,$bg) = @{ $cols->{vcc} };
205                 rect $x,$y,$col,$bg;
206                 return qq{ style="fill:$fg"};
207         } elsif ( $name =~ m/(G(ND|Round)|VSS)/i ) {
208                 my ($fg,$bg) = @{ $cols->{gnd} };
209                 rect $x,$y,$col,$bg;
210                 return qq{ style="fill:$fg"};
211         } elsif ( $name =~ m/\[(\w+)\d/ ) { # kernel
212                 my $dev = $1;
213                 if ( my ($fg,$bg) = @{ $cols->{$dev} } ) {
214                         rect $x,$y,$col,$bg;
215                         return qq{ style="fill:$fg"};
216                 }
217         } else {
218                 my ( $fg, $bg ) = @{ $cols->{txt} };
219                 rect $x,$y,$col,$bg;
220                 #return qq{ style="fill:$fg"};
221                 return '';
222         }
223 }
224
225 my $alt_col = 0;
226
227 my @cols_order = ( 0,1,2,3 );
228 my @cols_align = ( '','-','','-' ); # sprintf prefix
229
230 @cols_order = ( 0,1,3,2 ); # pins outside on the right
231 @cols_align = ( '','-','-','' );
232
233
234 # cut marks
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};
237
238 my @cut_marks;
239 sub cut_mark {
240         my ($x,$y) = @_;
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);
244 }
245 cut_mark $x, $y;
246 my $max_x = $x;
247 $max_x += $max_len[$_] * $font_w foreach ( 0 .. 3 );
248 cut_mark $max_x, $y;
249
250 my $last_cut_mark = 0;
251
252 foreach my $i ( 0 .. $#line_parts ) {
253         $i = $#line_parts - $i if $opt_vertical;
254         my $line = $line_parts[$i];
255
256         if ( $opt_svg ) {
257
258                 if ( ! exists $line->[0] ) {
259                         # before first empty line
260                         if ( $last_cut_mark == 0 ) {
261                                 cut_mark $x, $y;
262                                 cut_mark $max_x, $y;
263                                 $last_cut_mark = 1;
264                                 $y += 15; # make spacing between pinouts
265                         }
266                 } elsif ( $last_cut_mark ) {
267                         # first full line
268                         cut_mark $x, $y;
269                         cut_mark $max_x, $y;
270                         $last_cut_mark = 0;
271                 } else {
272                         warn "CUTMARK no magic";
273                 }
274
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};
277
278                 my $x_pos = $x;
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;
285                 }
286
287                 $tspan .= qq{</tspan>\n};
288                 push @later,sprintf $tspan, @$line;
289                 $y += 2.54;
290
291                 # swap pin colors for line stripes
292                 swap_cols $_ foreach qw( pins txt );
293
294         } else {
295
296                 if ( $#$line == 0 ) {
297                         print $line->[0], "\n";
298                 } else {
299                         push @$line, '' while ($#$line < 3); # fill-in single row header
300                         printf $fmt, @$line;
301                 }
302
303         }
304 }
305
306 if ( $opt_svg ) {
307         print qq{
308     <text
309        id="text4506"
310        y="$x"
311        x="$y"
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">
314
315         }; #svg
316
317         print @later, @cut_marks, qq{
318 </text>
319 </g>
320 </svg>
321         }; #svg
322
323 }
324
325 __DATA__
326 # Cubietech Cubieboard2
327 ## U14 (Next to SATA connector)
328 ###     SPI0
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)
331 ###     LCD
332 44      3.3V (nc in 2012-08-08)                 43      VCC-5V
333 42      Ground                                  41      SPDIF
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)
354
355 # Cubietech Cubieboard2
356 ## U15 (Between Ethernet port and USB ports)
357 ### CSI1/TS
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)
367 19      Ground                                  20      Ground
368 ###     Analog SDIO3
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)
375 ###     CSI0/TS
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)
384
385 ## DEBUG serial (middle of board)
386 4       PB22 (UART0-TX)
387 3       PB23 (UART0-RX)
388 2       VCC-3V3
389 1       GND
390
391
392 # Lamobo R1
393 ## CON3 rpi DIP26-254
394 1       3.3v                    2       5v     
395 3       PB20 SDA.1              4       5V     
396 5       PB21 SCL.1              6       0v     
397 7       PI3 PWM1                8       PH0 UART3_TX
398 9       0v                      10      PH1 UART3_RX
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
407
408 ## J13 DIP2-254
409 2       PB22 UART0_TX
410 1       PB23 UART0_RX
411
412 ## J12 DIP8-254
413 8       GND                     7       GND
414 6       PI20 UART7_TX           5       PH3
415 4       PI21 UART7_RX           3       PH5
416 2       3V3                     1       SATA-5V
417
418 # Raspberry Pi 3 Model B Rev 1.2
419 1       3.3v                    2       5v
420 3       gpio2 (SDA.1)           4       5v
421 5       gpio3 (SCL.1)           6       0v
422 7       gpio4 (GPIO. 7)         8       gpio14  (TxD)
423 9       0v                      10      gpio15  (RxD)
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)
431 25      0v                      26      gpio7   (CE1)
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)