added 0v and 5v
[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 my $device;
69
70 open(my $fh, '<', '/sys/kernel/debug/pinctrl/pinctrl-handles');
71 while(<$fh>) {
72         chomp;
73         if ( m/device: [0-9a-f]+\.(\w+)/ ) {
74                 $device = $1;
75         } elsif ( m/group: (\w+\d+)\s.+function: (\S+)/ ) {
76                 my ($pin, $function) = ($1,$2);
77                 $pin_function->{$pin} = "$device $function";
78
79                 next unless $opt_kernel;
80
81                 if ( $pins->{$pin} ) {
82                         foreach my $line ( @{$pins->{$pin}} ) {
83 warn "XXX $pin $line";
84                                 my $t = $lines[$line];
85                                 if ( $opt_svg ) {
86                                         $t =~ s/$pin/[$device $function]/;
87                                 } else {
88                                         $t =~ s/$pin/$pin [$device $function]/ || die "can't find $pin in [$t]";
89                                 }
90                                 $lines[$line] = $t;
91                                 warn "# $line: $lines[$line]\n";
92                         }
93                 } else {
94                         warn "IGNORED: pin $pin function $function\n";
95                 }
96         }
97 }
98
99 warn "# pin_function = ",dump($pin_function);
100
101 my @max_len = ( 0,0,0,0 );
102 my @line_parts;
103 foreach my $line (@lines) {
104         if ( $line =~ m/^#/ ) {
105                 push @line_parts, [ $line ] unless $opt_svg;
106                 next;
107         }
108         $line =~ s/(\[(:?uart|serial))([^\t]*\]\s[^\t]*(rx|tx)d?)/$1 $3$2/gi;
109         $line =~ s/(\[i2c)([^\t]*\]\s[^\t]*(sclk?|sda))/$1 $3$2/gi;
110         $line =~ s/(\[spi)([^\t]*\]\s[^\t]*(miso|mosi|s?clk|c[se]\d*))/$1 $3$2/gi;
111         $line =~ s/\s*\([^\)]+\)//g if ! $opt_alt;
112
113         my @v = split(/\s*\t+\s*/,$line,4);
114         push @line_parts, [ @v ];
115         foreach my $i ( 0 .. 3 ) {
116                 next unless exists $v[$i];
117                 next if $v[$i] =~ m/^#/; # don't calculate comments into max length
118                 my $l = length($v[$i]);
119                 $max_len[$i] = $l if $l > $max_len[$i];
120         }
121 }
122
123 warn "# max_len = ",dump( \@max_len );
124 warn "# line_parts = ",dump( \@line_parts );
125
126 #print "$_\n" foreach @lines;
127
128 my $fmt = "%$max_len[0]s %-$max_len[1]s %$max_len[2]s %-$max_len[3]s\n";
129
130 my $x = 30.00; # mm
131 my $y = 30.00; # mm
132
133 if ( $opt_svg ) {
134         print qq{<?xml version="1.0" encoding="UTF-8" standalone="no"?>
135 <svg
136    xmlns:dc="http://purl.org/dc/elements/1.1/"
137    xmlns:cc="http://creativecommons.org/ns#"
138    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
139    xmlns:svg="http://www.w3.org/2000/svg"
140    xmlns="http://www.w3.org/2000/svg"
141    xmlns:xlink="http://www.w3.org/1999/xlink"
142    id="svg8"
143    version="1.1"
144    viewBox="0 0 210 297"
145    height="297mm"
146    width="210mm">
147
148
149 <g id="layer1">
150
151         }; # svg, insert rest of rect
152
153         print qq{<rect x="0" y="0" width="210" height="297" style="fill:#000000" id="high-contrast"/>} if $opt_invert;
154 }
155
156 my @later;
157
158 my $cols = {    # foreground background
159         txt  => [ '#000000', '#ffffff' ],
160         pins => [ '#ffffff', '#ff00ff' ],
161         vcc  => [ '#ff0000', '#ffff00' ],
162         gnd  => [ '#000000', '#00ffff' ],
163         i2c  => [ '#008800', '#ffcccc' ],
164         uart => [ '#000088', '#ccffcc' ],
165         spi  => [ '#880000', '#ccccff' ],
166 };
167
168 sub swap_cols {
169         my $swap = shift;
170         die "$swap not found in ",dump($cols) unless $cols->{$swap};
171         my ( $c1, $c2 ) = @{ $cols->{$swap} };
172         $cols->{$swap} = [ $c2, $c1 ];
173 }
174
175 swap_cols 'txt' if $opt_invert;
176         
177
178 sub svg_style {
179         my ($name,$x,$y,$col) = @_;
180         $y -= $font_b; # shift box overlay to right vertical position based on font baseline
181
182         sub rect {
183                 my ($x,$y,$col,$fill) = @_;
184                 print qq{<rect x="$x" y="$y" height="2.54" width="}, $max_len[$col] * $font_w, qq{" style="fill:$fill;stroke:#ffffff;stroke-width:0.10" />\n};
185
186         }
187
188         if ( $name =~ m/^(\d+)$/ ) { # pins
189                 my $pin = $1;
190                 my ( $fg, $bg ) = @{ $cols->{pins} };
191                 if ( $pin == 1 ) {
192                         my $w  = $max_len[$col]*$font_w - 0.1;
193                         my $cx = $x + $w;
194                         my $cy = $y + 2.54;
195                         #print qq{<polygon points="$x,$y $cx,$y $x,$cy $x,$y" stroke="$fg" stroke-width="0.25" fill="$bg" />};
196                         #print qq{<polygon points="$x,$cy $cx,$cy $cx,$y $x,$cy" stroke="$bg" stroke-width="0.25" fill="$fg" />};
197                         print qq{<rect x="$x" y="$y" width="$w" height="2.54" stroke="$fg" stroke-width="0.3" fill="$bg" />};
198                         my ( $fg, $bg ) = @{ $cols->{txt} };
199                         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                 } else {
201                         rect $x,$y,$col,$fg;
202                 }
203                 return qq{ style="fill:$bg"};
204         }
205
206         if ( $name =~ m/(VCC|3V3|3.3V|5v)/i ) {
207                 my ($fg,$bg) = @{ $cols->{vcc} };
208                 rect $x,$y,$col,$bg;
209                 return qq{ style="fill:$fg"};
210         } elsif ( $name =~ m/(G(ND|Round)|VSS|0v)/i ) {
211                 my ($fg,$bg) = @{ $cols->{gnd} };
212                 rect $x,$y,$col,$bg;
213                 return qq{ style="fill:$fg"};
214         } elsif ( $name =~ m/\[(\w+)\d/ ) { # kernel
215                 my $dev = $1;
216                 my ($fg,$bg) = @{ $cols->{txt} };
217                 ($fg,$bg) = @{ $cols->{$dev} } if exists $cols->{$dev};
218                 rect $x,$y,$col,$bg;
219                 return qq{ style="fill:$fg"};
220         } else {
221                 my ( $fg, $bg ) = @{ $cols->{txt} };
222                 rect $x,$y,$col,$bg;
223                 #return qq{ style="fill:$fg"};
224                 return '';
225         }
226 }
227
228 my $alt_col = 0;
229
230 my @cols_order = ( 0,1,2,3 );
231 my @cols_align = ( '','-','','-' ); # sprintf prefix
232
233 @cols_order = ( 0,1,3,2 ); # pins outside on the right
234 @cols_align = ( '','-','-','' );
235
236
237 # cut marks
238 my ($fg,$bg) = @{ $cols->{txt} };
239 my $line_fmt = qq{<line x1="%s" y1="%s" x2="%s" y2="%s" style="stroke:$fg;stroke-width:0.10;fill:$bg" />\n};
240
241 my @cut_marks;
242 sub cut_mark {
243         my ($x,$y) = @_;
244         return unless $opt_svg;
245         push @cut_marks, sprintf($line_fmt, $x-5, $y-$font_b,   $x+5, $y-$font_b);
246         push @cut_marks, sprintf($line_fmt, $x,   $y-$font_b-5, $x,   $y-$font_b+5);
247 }
248 cut_mark $x, $y;
249 my $max_x = $x;
250 $max_x += $max_len[$_] * $font_w foreach ( 0 .. 3 );
251 cut_mark $max_x, $y;
252
253 my $last_cut_mark = 0;
254
255 foreach my $i ( 0 .. $#line_parts ) {
256         $i = $#line_parts - $i if $opt_vertical;
257         my $line = $line_parts[$i];
258
259         if ( $opt_svg ) {
260
261                 if ( ! exists $line->[0] ) {
262                         # before first empty line
263                         if ( $last_cut_mark == 0 ) {
264                                 cut_mark $x, $y;
265                                 cut_mark $max_x, $y;
266                                 $last_cut_mark = 1;
267                                 $y += 15; # make spacing between pinouts
268                         }
269                 } elsif ( $last_cut_mark ) {
270                         # first full line
271                         cut_mark $x, $y;
272                         cut_mark $max_x, $y;
273                         $last_cut_mark = 0;
274                 } else {
275                         #warn "CUTMARK no magic";
276                 }
277
278                 my ($fg,$bg) = @{ $cols->{txt} };
279                 my $tspan = qq{<tspan x="$x" y="$y" style="line-height:2.54;fill:$fg;stroke:none;">\n};
280
281                 my $x_pos = $x;
282                 foreach my $i ( @cols_order ) {
283                         next unless $line->[$i];
284                         my $text_anchor = 'middle';
285                         my $x2 = $x_pos + ( $max_len[$i] * $font_w ) / 2;
286                         $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]);
287                         $x_pos += $max_len[$i] * $font_w;
288                 }
289
290                 $tspan .= qq{</tspan>\n};
291                 push @later,sprintf $tspan, @$line;
292                 $y += 2.54;
293
294                 # swap pin colors for line stripes
295                 swap_cols $_ foreach qw( pins txt );
296
297         } else {
298
299                 if ( $#$line == 0 ) {
300                         print $line->[0], "\n";
301                 } else {
302                         push @$line, '' while ($#$line < 3); # fill-in single row header
303                         printf $fmt, @$line;
304                 }
305
306         }
307 }
308
309 if ( $opt_svg ) {
310         print qq{
311     <text
312        id="text4506"
313        y="$x"
314        x="$y"
315        style="font-size:2.34px;line-height:2.54px;font-family:'Andale Mono';stroke:none"
316        xml:space="preserve">
317
318         }; #svg
319
320         print @later, qq{</text>\n}, @cut_marks, qq{</g>\n</svg>};
321
322 }
323
324 __DATA__
325 # Cubietech Cubieboard2
326 ## U14 (Next to SATA connector)
327 ###     SPI0
328 48      PI13 (SPI0-MISO/UART6-RX/EINT25)        47      PI11 (SPI0-CLK/UART5-RX/EINT23)
329 46      PI12 (SPI0-MOSI/UART6-TX/EINT24)        45      PI10 (SPI0-CS/UART5-TX/EINT22)
330 ###     LCD
331 44      3.3V (nc in 2012-08-08)                 43      VCC-5V
332 42      Ground                                  41      SPDIF
333 40      PB10 (LCD0-SCK/LCD-PIO1)                39      PB11 (LCD0-SDA/LCD-PIO2)
334 38      Ground                                  37      PH7 (LCD0-BL-EN/LCD-PIO0/UART5-RX/EINT7)
335 36      XN_TP (TP-X2)                           35      YN_TP (TP-Y2)
336 34      XP_TP (TP-X1)                           33      YP_TP (TP-Y1)
337 32      PD25 (LCDDE)                            31      PB2 (PWM0)
338 30      PD26 (LCDHSYNC/VGA-HSYNC)               29      PD24 (LCDCLK)
339 28      PD23 (LCDD23)                           27      PD27 (LCDVSYNC/VGA-VSYNC)
340 26      PD21 (LCDD21)                           25      PD22 (LCDD22)
341 24      PD19 (LCDD19/LVDS1N3)                   23      PD20 (LCDD20)
342 22      PD17 (LCDD17/LVDS1NC)                   21      PD18 (LCDD18/LVDS1P3)
343 20      Ground                                  19      PD16 (LCDD16/LVDS1PC)
344 18      PD14 (LCDD14/LVDS1P2)                   17      PD15 (LCDD15/LVDS1N2)
345 16      PD12 (LCDD12/LVDS1P1)                   15      PD13 (LCDD13/LVDS1N1)
346 14      PD10 (LCDD10/LVDS1P0)                   13      PD11 (LCDD11/LVDS1N0)
347 12      PD8 (LCDD8/LVDS0P3)                     11      PD9 (LCDD9/LVDS0N3)
348 10      PD7 (LCDD7/LVDS0NC)                     9       Ground
349 8       PD5 (LCDD5/LVDS0N2)                     7       PD6 (LCDD6/LVDS0PC)
350 6       PD3 (LCDD3/LVDS0N1)                     5       PD4 (LCDD4/LNVS0P2)
351 4       PD1 (LCDD1/LVDS0N0)                     3       PD2 (LCDD2/LVDS0P1)
352 2       Ground                                  1       PD0 (LCDD0/LVDSP0)
353
354 # Cubietech Cubieboard2
355 ## U15 (Between Ethernet port and USB ports)
356 ### CSI1/TS
357 1       VCC-5V                                  2       PH15 (CSI1-PWR/EINT15)
358 3       CSI1-IO-2V8                             4       PH14 (CSI1-RST#/EINT14)
359 5       PG0 (CSI1-PCLK/SDC1-CMD)                6       PB18 (TWI1-SCK)
360 7       PB19 (TWI1-SDA)                         8       PG3 (CSI1-VSYNC/SDC1-D1)
361 9       PG2 (CSI1-HSYNC/SDC1-D0)                10      PG1 (CSI1-MCLK/SDC1-CLK)
362 11      PG4 (CSI1-D0/SDC1-D2)                   12      PG5 (CSI1-D1/SDC1-D3)
363 13      PG6 (CSI1-D2/UART3-TX)                  14      PG7 (CSI1-D3/UART3-RX)
364 15      PG8 (CSI1-D4/UART3-RTS)                 16      PG9 (CSI1-D5/UART3-CTS)
365 17      PG10 (CSI1-D6/UART4-TX)                 18      PG11 (CSI1-D7/UART4-RX)
366 19      Ground                                  20      Ground
367 ###     Analog SDIO3
368 21      FMINL                                   22      PI4 (SDC3-CMD)
369 23      FMINR                                   24      PI5 (SDC3-CLK)
370 25      Ground                                  26      PI6 (SDC3-D0)
371 27      VGA-R                                   28      PI7 (SDC3-D1)
372 29      VGA-G                                   30      PI8 (SDC3-D2)
373 31      VGA-B                                   32      PI9 (SDC3-D3)
374 ###     CSI0/TS
375 33      LCD1-VSYNC                              34      PE4 (CSI0-D0)
376 35      LCD1-HSYNC                              36      PE5 (CSI0-D1)
377 37      Ground                                  38      PE6 (CSI0-D2)
378 39      AVCC                                    40      PE7 (CSI0-D3)
379 41      LRADC0                                  42      PE8 (CSI0-D4)
380 43      CVBS                                    44      PE9 (CSI0-D5)
381 45      HPL                                     46      PE10 (CSI0-D6)
382 47      HPR                                     48      PE11 (CSI0-D7)
383
384 ## DEBUG serial (middle of board)
385 4       PB22 (UART0-TX)
386 3       PB23 (UART0-RX)
387 2       VCC-3V3
388 1       GND
389
390
391 # Lamobo R1
392 ## CON3 rpi DIP26-254
393 1       3.3v                    2       5v     
394 3       PB20 SDA.1              4       5V     
395 5       PB21 SCL.1              6       0v     
396 7       PI3 PWM1                8       PH0 UART3_TX
397 9       0v                      10      PH1 UART3_RX
398 11      PI19 UART2_RX           12      PH2
399 13      PI18 UART2_TX           14      0v     
400 15      PI17 UART2_CTS          16      PH21 CAN_RX 
401 17      3.3v                    18      PH20 CAN_TX 
402 19      PI12 SPI0_MOSI          20      0v     
403 21      PI13 SPI0_MISO          22      PI16 UART2_RTS   
404 23      PI11 SPI0_SCLK          24      PI10 SPI0_CS0    
405 25      0v                      26      PI14 SPI0_CS1
406
407 ## J13 DIP2-254
408 2       PB22 UART0_TX
409 1       PB23 UART0_RX
410
411 ## J12 DIP8-254
412 8       GND                     7       GND
413 6       PI20 UART7_TX           5       PH3
414 4       PI21 UART7_RX           3       PH5
415 2       3V3                     1       SATA-5V
416
417 # Raspberry Pi 3 Model B Rev 1.2
418 1       3.3v                    2       5v
419 3       gpio2 (SDA.1)           4       5v
420 5       gpio3 (SCL.1)           6       0v
421 7       gpio4 (GPIO. 7)         8       gpio14  (TxD)
422 9       0v                      10      gpio15  (RxD)
423 11      gpio17 (GPIO. 0)        12      gpio18  (GPIO. 1)
424 13      gpio27 (GPIO. 2)        14      0v
425 15      gpio22 (GPIO. 3)        16      gpio23  (GPIO. 4)
426 17      3.3v                    18      gpio24  (GPIO. 5)
427 19      gpio10 (MOSI)           20      0v
428 21      gpio9 (MISO)            22      gpio25  (GPIO. 6) 
429 23      gpio11 (SCLK)           24      gpio8   (CE0)
430 25      0v                      26      gpio7   (CE1)
431 27      gpio0 (SDA.0)           28      gpio1   (SCL.0)
432 29      gpio5 (GPIO.21)         30      0v
433 31      gpio6 (GPIO.22)         32      gpio12  (GPIO.26)
434 33      gpio13 (GPIO.23)        34      0v
435 35      gpio19 (GPIO.24)        36      gpio16  (GPIO.27)
436 37      gpio26 (GPIO.25)        38      gpio20  (GPIO.28)
437 39      0v                      40      gpio21  (GPIO.29)